Skip navigation.

Fat R笔记……与减肥无关

Fat awful terrible Rubbish-bin

Posts tagged with "hardware"

使用SATA硬盘后的待机问题

,

我的主机(Epox的9nda3i,NForce3芯片组)原先采用的是两块PATA硬盘,现在由于其中一块烧掉了 (意味着JavaMagic有排不能更新了,虽然现在我也没空去更新……)换成了一块SATA

可是问题来了,换了SATA后待机居然就不能正常唤醒了,要么开机后屏幕黑掉只剩鼠标指针可以动,要么就是可以看到wallpaper,但仍然只有鼠标可以动。后来重新装了一个系统,稍微好一些,唤醒时可以看见登录框,但输入密码后就freeze了,现象很像以前硬盘掉电造成的freeze。于是就怀疑起硬盘来,后来发现把PATA拔了居然就可以正常待机并唤醒了,但只要插上PATA就必然不行(我试过手上若干能被BIOS辨认出来的PATA都这样,只有BIOS辨认不出来的才能幸免)。

由于不知道到底是跟BIOS有关还是跟驱动有关,现在又是赶论文的关键时期,不敢赌rp去烧bios,于是只好尝试不同的驱动版本。然而试了n款,包括非官方和官方的,无论新旧,都存在这个问题。后来发现,把NForce的SW IDE驱动卸载,用回系统自带的atapi驱动居然就正常了,唯一不爽的地方是开机进系统的时候要检测n久。

再后来,发现用SW IDE驱动时,在BIOS里面把PATA硬盘设置成None,居然也可以待机了。不过那破驱动会把硬盘的Transfer Mode自动检测成DMA 2,要在设备管理器那里去掉"Let BIOS select transfer mode",并手动指定成最高的传输模式。虽然还是不爽,不过也只能这样将就用着先了。

另外,在网上搜索了一下,似乎讨厌NForce SW IDE驱动的人也不少。这里还有一个有趣的benchmark,似乎系统自带的驱动性能也不差嘛……
http://www.nforcershq.com/forum/benchmark-ms-ide-vs-nforce-ide-updated-vt56754.html

这里讲到了卸载NForce IDE驱动的方法:
http://forums.nvidia.com/lofiversion/index.php?t12773.html
即,可以在添加删除程序那里用卸载程序卸,也可以在设备管理器的IDE ATA/ATAPI控制器下,选择右键菜单的“更新设备驱动”,在向导中选择指定安装,不要搜索,然后就可以在向导里看到“标准双通道PCI IDE控制器”,也就是系统自带的驱动了。

摸了一下hharm-2410核心板

没有深入研究,总结一下(其实也是常见的问题)



一.丢失引导:
华恒论坛在新版本的ppcboot中的说明如下:

近来不断有客户反映,s3c2410的一些开发板有时会莫名的丢失引导。一开始我们以为是客户不熟悉操作,不小心误操作的结果,但经过一段时间的多方检测,发现这里不仅仅是误操作这么简单;我们通过对这方面的问题收集,并结合客户反馈的若干想法和建议,我们总结后发现这不单单是s3c2410相关开发板的问题,还包括ppc8250、xscale425、s3c2440、mxl9328、arm9200等,都有类似问题出现过。通过对这类板卡的分析发现这类板卡都有一个共性,就是他们的rom存储都是采用的intel e28f128 这款flash;再者了解到e28f128这款flash的控制时序相对比较简单很可能也是导致这个问题发生重要原因。

更改后的ppcboot.bin在当前的使用上做如下调整
原先的引导、内核、文件系统的起始地址分别为1000000、1040000、1140000,现在分为0、40000、140000
……


以一下所提到的所有问题已经得到了彻底的解决,尤其让我们高兴的是早期对intel的这款e28f128 flash 始终支持的不是很好(这块flash往往擦写几十次可能就坏了,这实际上是这块flash的操作时序太简单所致,这也是采用这款flash的所有商家的共同问题。),我们通过多方努力,今天终于做到了性能上的突破。

现有的HHARM2410使用的是3 Volt Intel StrataFlash Memory device, 该Flash Memory提供安全模式(Security Mode),可以保护Flash中的数据防止被意外删除或重写。但是现在的 ppcboot for HHARM2410 版本并没有实现此保护功能,造成的后果是某些重要代码烧写到Flash中之后,如果后续程序跑飞,很可能会冲掉之前烧入的重要代码。这类错误很难发现而且后果通常比较严重。
针对以上问题,对现有的ppcboot for HHARM2410代码进行改进,使之可以实现保护Flash中的数据防止被意外删除或重写的功能就显得十分必要。
……



那块板的ppcboot烧写基地址是0x1000000,那么就是没有写保护的旧版了……

但不太清楚到底什么情况下可以改写flash的东西(NOR flash是可以随机读写的,但擦除只能以block为单位进行——这是否意味着,以正常方式对某个地址进行写操作,并不存在判断该地址数据是否为0xff的过程,只要有为"1"的bit就可能可以改变对应字节的内容呢?)

在丢失引导之前曾经执行过loadb 8000(之前设置了base 30000000,然而这个设置居然是对loadb无效的,而loadb命令在下载前也不会提示,所以下载完看到统计信息才知道地址错了),不知道是不是就是这个指令冲掉了引导……

而更神奇的是,后来我把ppcboot烧回去了,发现不但ppcboot没有了,kernel、initrd、jffs2等所有分区都被破坏了(某些字节被改写),难道是丢失引导后ppcboot跑飞,到处乱写了东西?


二.JTAG:
核心板的JTAG connector是10pin的那种,而且size特别小,由于找不到这种插头,最后同事硬是用两个差不多孔距的插头插了上去,把那几根线引到了另一个大的20pin connector上。DB25-JTAG用的是同时有Wiggler、STD、S3C2410三种接口的那个转换板。一开始接的是Wiggler,调试代理能认到CPU,H-JTAG也能,但就是sjf2410死活认不出来。开始怀疑是延串口长线、giveio甚至是系统的问题(调试用机,啥问题都有可能出现),但用一个测试程序去测,giveio是正常的,而且换到linux下甚至到另外一台win2k下,sjf2410都依然固执地不认cpu。后来再认真看看sjf2410的文档才醒悟过来可能是db25那边的Pin Assignment的问题。另外,后来才看到那个转接板配套的ARM9开发板的文档里其实已经指出,使用sjf2410时要把20针排线接到S3C2410的接口上……其实还是自己以前对JTAG的认识不够全面造成的问题,还好最终能够及时发现。


三.SJF2410 & 28F128J3A:
解决JTAG的问题后,SJF2410在dos下总算能认cpu了(可是Linux下面依然认不出来。。。难道华恒的程序改了Pin Assignment?或者系统本身的问题?),然而在检测Flash型号的时候,ID认出来0x89,但Device类型却认不出来。对照strata32.c和28F128J3A的datasheet,读取Identifier Codes的方法应该是先向任意地址写0x90(见Datasheet的Table 4. Command set definitions),然后读地址00000,可得到ID号0x89,而地址00001则读到Device Code,128Mbit对应的是0x18(见Table 5. Identifier Codes)。Table 5中还提到,那两个地址的最低位是A1,A0在x16模式(即16位模式)下被忽略了。Strata的代码原来是这么写的:
int Strata_CheckDevice(int targetAddr) 
{
    //_RESET();
    _WR(targetAddr, 0x00900090);
    return _RD(targetAddr+0x4);
}

试着把0x4改成0x2,果然可以读出来了,接着就自动开始了烧写。然而烧完后用内存读写功能查看,发现烧进去的东西每隔两个字节就是两个0xFF,即11 22 FF FF 55 66 FF FF 99 AA这样。再仔细阅读一下Strata.c,才发现原来这个程序对应的硬件配置是16x2,即用2片flash接成32bit的形式,一片是低16bit一片是高16bit,sjf2410也是以32bit的宽度进行读写。例如上面的_WR(targetAddr, 0x00900090);实际上就是向targetAddr开始的4个字节写入数据,也就是分别向两片flash写入16bit数0x0090(其实这从代码的注释中也可以看出来)。targetAddr仍然是按字节编码的,对于16x2的配置,每次写入32bit,地址就要+4,因此用这样的代码对16x1的配置进行烧写,就会每次只烧入了低16位,高16位没烧,而地址的增量仍然是4,于是就会出现每2字节间隔2个ff的现象。
也就是说,16x2的地址分布是这样的(假设基地址是00000000):

---mem-------flash--
0000 0000 - 0:000000
0000 0001 - 0:000001
0000 0002 - 1:000000
0000 0003 - 1:000001
0000 0004 - 0:000002
0000 0005 - 0:000003
0000 0006 - 1:000002
0000 0007 - 1:000003
....

由于flash是16位,所以其地址线的A0被忽略,也就是说000000和000001实际上都是同一个地址,左移一位后都是00000。
而16x1的地址分布是:

---mem-------flash--
0000 0000 - 0:000000
0000 0001 - 0:000001
0000 0002 - 0:000002
0000 0003 - 0:000003
0000 0004 - 0:000004
0000 0005 - 0:000005
0000 0006 - 0:000006
0000 0007 - 0:000007
....

所以,把烧写部分的代码改写成这样就行了:
    for (i=0; i<targetSize; i+=2) 
    {
        Strata_ProgFlash(i+targetAddress+targetOffset, (*((U16 *)(srcAddr+i)))&0xffff);        
        //if((i%0x100)==0xfc)
        if((i&0xff)==0xfe)
            printf("[%x]",i+2);
    }

读数也一样,根据datasheet,读Device Code的地址是0x00001,加上忽略掉的A0,就是0x00001 << 1。而在16x2的配置下,根据上面的地址应设表,0x0000 0002和0x0000 0003实际上对应高16bit的0x00000地址(忽略A0),0x0000 0004和0x0000 0005对应的才是低16bit flash的0x00001地址(忽略A0)。因此16x2读Device Code是_RD(targetAddr+0x4),16x1应该改成_RD(targetAddr+0x2)。

至于擦除,由于是按block进行的,根据28F128J3A的datasheet,它分为128个block,每个block为1Mbit,即128kb(0x20000字节),所以擦除部分的代码应该为:
    for(i=0;i<targetSize;i+=0x20000)
    {
//Strata_ClearBlockLock(targetAddress+targetOffset+i); 
      Strata_EraseSector(targetAddress+targetOffset+i);
    }

当然,Strata_EraseSector也要进行修改,不然擦除的时候就可能跳不出里面那个while循环:
void Strata_EraseSector(int targetAddress) 
{
    unsigned long ReadStatus;
    unsigned long bSR5;     // Erase and Clear Lock-bits Status, lower 16bit, 8MB Intel Strate Flash ROM
    unsigned long bSR5_2;   // Erase and Clear Lock-bits Status, higher 16bit, 8MB Intel Strate Flash ROM
    unsigned long bSR7;     // Write State Machine Status, lower 16bit, 8MB Intel Strate Flash ROM
    unsigned long bSR7_2;   // Write State Machine Status, higher 16bit, 8MB Intel Strate Flash ROM
    //_RESET();
//  _WR(targetAddress, 0x00200020);
//  _WR(targetAddress, 0x00d000d0);
    _WR(targetAddress, 0x0020); // Block Erase, First Bus Cycle, targetAddress is the address withint the block
    _WR(targetAddress, 0x00d0); // Block Erase, Second Bus Cycle, targetAddress is the address withint the block
    
    //_RESET();
    _WR(targetAddress, 0x0070); // Read Status Register, First Bus Cycle, targetAddress is any valid address within the device
    ReadStatus=_RD(targetAddress);  // Read Status Register, Second Bus Cycle, targetAddress is any valid address within the device
    bSR7=ReadStatus & (1<<7);       // lower 16-bit 8MB Strata
    //bSR7_2=ReadStatus & (1<<(7+16));// higher 16-bit 8MB Strata
    //while(!bSR7 || !bSR7_2) 
    while(!bSR7) 
    {
        _WR(targetAddress, 0x0070);
        ReadStatus=_RD(targetAddress);
        bSR7=ReadStatus & (1<<7);
        //bSR7_2=ReadStatus & (1<<(7+16));
      //printf("wait\n");
    }

    _WR(targetAddress, 0x0070); // When the block erase is complete, status register bit SR.5 should be checked. 
                    // If a block erase error is detected, the status register should be cleared before
                    // system software attempts correct actions.
    ReadStatus=_RD(targetAddress);  
    bSR5=ReadStatus & (1<<5);           // lower 16-bit 8MB Strata 
    //bSR5_2=ReadStatus & (1<<(5+16));    // higher 16-bit 8MB Strata 
    //if (bSR5==0 && bSR5_2==0) 
    if (bSR5==0) 
    {
        printf("Block @%xh Erase O.K. \n",targetAddress);
    } 
    else 
    {
        //printf("Error in Block Erasure!!\n");
        _WR(targetAddress, 0x0050); // Clear Status Register
        error_erase=1;                  // But not major, is it casual ?
    }

    _RESET();   // write 0xffh(_RESET()) after the last opoeration to reset the device to read array mode.
}


另外,烧写flash可能初始化时需要对cpu的某些寄存器进行设置。在FlashPGM里,虽然可以识别cpu,但烧写总是不顺利,应该是cpu寄存器没有设置好的原因。由于时间关系,没有对这个问题进行深入研究……

由于sjf2410开放源代码,因此很容易就可以将其修改得适应自己的硬件设置,也可以很容易地增加功能。例如我在内存读写那里加入了一个df指令,用来把flash的内容dump出来(当然,如果能进linux,直接把mtd设备内容dump出来保存到u盘上是最快的做法)。
--- sjf2410_ori/mem_rdwr.c      2002-11-15 08:29:02.000000000 +0800
+++ sjf2410/mem_rdwr.c  2006-09-18 19:34:04.000000000 +0800
@@ -19,7 +19,7 @@
 {
     int i,j;
     char command[128];
-    U32 addr;
+    U32 addr, len;
     U8 dataByte;
     U16 dataHW;
     U32 dataWord;
@@ -49,6 +49,7 @@
            printf("| wb <hex_addr> <hex_data>: write, byte data                 |\n");
            printf("| wh <hex_addr> <hex_data>: write, half-word data            |\n");
            printf("| ww <hex_addr> <hex_data>: write, word data                 |\n");
+        printf("| df <hex_addr> <len>     : dump to file                     |\n");
            printf("+-------------------------- NOTE ----------------------------+\n");
            printf("| 1. nGCS6,7 SDRAM read/write isn't supported now.           |\n");
            printf("| 2. example: >bs 2 16 1                                     |\n");
@@ -76,10 +77,47 @@
            break;

        case 'd':
+        if(command[1] == 'f'){
+          FILE *fp;
+          char filename[FILENAME_MAX];
+          scanf("%x %x",&addr, &len);
+          addr=addr&0xfffffffe; //ignore A[0]
+          bank=S2410_Addr2Bank(addr);
+          i = addr + len;
+          j = 0;
+          printf("Please wait...\n");
+          sprintf(filename,"dump_%X_%X",addr,len);
+          fp = fopen(filename,"wb");
+          if(fp==NULL){
+            printf("Failed to open %s for writing!\n",filename);
+            break;
+          }
+          while(addr < i){
+            if (j != ((addr>>8)&1)){
+              j = ((addr>>8)&1);
+              printf("[%8x]",addr);
+              fflush(fp);
+            }
+            //error=MRW_RdByte(addr++,&dataByte);
+            error=MRW_RdHW(addr,&dataHW);
+            addr+=2;
+            if(error!=0)
+              printf("?? ");
+            else{
+              //printf("%04x ",dataHW);
+              fputc(dataHW&0xff,fp);
+              fputc((dataHW>>8)&0xff,fp);
+            }
+            //printf(".");
+          }
+          printf("\nDumped to %s\n",filename);
+          fclose(fp);
+          break;
+        }
            scanf("%x",&addr);
            addr=addr&0xfffffff0;
            bank=S2410_Addr2Bank(addr);
-           for(i=0;i<4;i++)
+        for(i=0;i<8;i++)
            {
                printf("%8x:",addr);
                for(j=0;j<16;j++)

其实我还打算加入烧写后自动为block加上写保护的功能的,不过由于现在不能碰那块板,于是只好放弃……反正新版本的ppcboot也可以方便地进行写保护嘛……


四.PPCBoot & Terminal software:
前面说了,ppcboot可以用loadb命令,通过串口以kermit协议下载.bin文件(但要注意那该死的base设置无效的bug)。由于windows自带的超级终端显示缓存的内容经常会乱掉,所以一直用的是Tera Term。但通过Tera Term把kernel下载到sdram中运行却怎么也跑不起来。经过观察,发现Tera term通过kermit传文件居然会丢包,于是后来只好改回超级终端,虽然传输速率比Tera Term低,但是却不会发生丢包的现象。

现在,至少有3种烧写flash的方法了:jtag、ppcboot、进入linux后写mtd设备
* jtag仅在丢失引导后重新烧写ppcboot使用,因为比较慢。
* 能够进入ppcboot后,就可以通过loadb从串口接收kernel和initrd(因为底板没有网口,不然就用tftp了),分别把它们放到30008 000和3080 0000的sdram空间(sdram接的片选是nGSC6,因此地址空间为0x3000 0000~0x37FF FFFF,具
体说明可以在华恒的手册上查到),然后bootm或者go 30008000就可以启动kernel进入系统。
* 进入系统后,如果kernel正常,可以通过u盘把jffs2和cramfs两个分区的img文件字节烧入相应flash分区。过程很简单:先umount掉/dev/mtdblock/4和/dev/mtdblock/5的挂载,然后把img文件复制到tmpfs中,再dd if=xxx.img of=/dev/mtd/4这样的命令烧写,烧写完后就可以重新挂载了。不过这里有个小问题,那块板最后两个分区默认下分别是jffs2和cramfs,如果用其它分区格式烧写,再挂载的时候,系统仍然会把它们识别成jffs2和cramfs(跟fstab无关的),必须用-t参数手动指定分区格式才能正常挂载。还有,mtdblock/4之前的分区都是不可写的,这意味着不能在linux下面通过写这几个分区来烧写ppcboot、kernel和ramdisk,应该能通过修改kernel去除这一限制(flash分区表是写在kernel里的,那么应该也可以通过kernel来让mtd分区只读)。

现在不知道是ppcboot还是kernel的问题,在默认情况下插入u盘会提示"usb.c: USB device not accepting new address",而启动后马上进入ppcboot,然后cp 1040000 30008000 e0000,cp 1140000 30800000 210000把kernel和ramdisk装入内存(ramdisk一定也要在内存中。另外,好玩的是,reset键复位并不会清除sdram的内容,所以cp之前可以先md一下看看内存中之前复制过去的ramdisk是否还健在——kernel基本上是不在的了,进入系统后30008000的内容就变了),接着go 30008000或者bootm进入系统才可以正常使用u盘。

另外,ppcboot在fc4下编译会出错,在华恒的论坛上,有人指出

在ppcboot-2.0.0/tools/gdb/astest.c
找到下面代码

printf("\tcooked_size=%ld, raw_size=%ld, output_offset=%ld\n",
(long)sect->_cooked_size , (long)sect->_raw_size,
(long)sect->output_offset);
改成
printf("\tcooked_size=%ld, raw_size=%ld, output_offset=%ld\n",
(long)sect->size, (long)sect->rawsize,
(long)sect->output_offset);


看了一下/usr/includ/bfd.h,应该就是2.6的typedef struct bfd_section定义改变了的原因。


五.Kernel:
kernel方面没进行太多的研究,所以笔记不多:
* USB Support那里的Maximum port(s) of RootHub要改成1,不然kernel会像疯子一样不停地抱怨连不上其它的port。
* General Setup的 Compressed boot loader in ROM/flash,选上之后似乎ppcboot就boot不了编译出来的kernel了(未确认,似乎而已,很可能那次boot不了是因为其它原因,只有等以后有机会并且可以用tftp传kernel的时候再进一步确认了。)
* 音频方面,Kernel那里只选上了OSS sound modules,声音驱动实际上是进入系统后用insmod /usr/2410audio.o另外加载的。其实很多设备的驱动都是进入系统后才挂的,可以参考华恒的手册。
* flash分区表在/drivers/mtd/maps/s3c2410_llg.c文件,可能可以通过修改这个文件来设置分区是否只读。

JTAG...

常见的JTAG cable结构都比较简单,一端是DB25,接到电脑的并口上,中间经过74HC244和一些电阻实现电平转换(5V<->3.3V?)(也有比较猥琐的只用了几个100 Ohm电阻的方案,似乎我这里用来烧CPLD的就是一条这样子的...),另一端的JTAG header接到目标板的JTAG interface。

并口DB25原先主要是用来连接打印机,其引脚定义如下:
25 Pin D-Sub SPP SIGNAL DIRECTION IN/OUT
1 /Strobe In/Out
2 Data 0 Out
3 Data 1 Out
4 Data 2 Out
5 Data 3 Out
6 Data 4 Out
7 Data 5 Out
8 Data 6 Out
9 Data 7 Out
10 /ACK In
11 Busy In
12 Paper Out In
13 Select In
14 /Line Feed In/Out
15 /Error In
16 /INIT In/Out
17 /Select In In/Out
18-25 Ground GND


可见,数据线Pin2~Pin9可以用来发送数据,Pin10~Pin13等可以用来接收数据。
JTAG的数据传输形式是串行,主要使用了以下引脚:
TDI (Test Data In)
TDO (Test Data Out)
TCK (Test ClocK)
TMS (Test Mode Select)
TRST (Test ReSeT) optional.

因此,DB25-JTAG实际上只利用了DB25的少数几根线。但由于DB25的8条数据线都可以作为output,市面上就出现了各种使用不同Pin Assignment的JTAG线。例如Wiggler的Pin assignment:
TMS   : Pin3 (D1)
TCK   : Pin4 (D2)
TDI   : Pin5 (D3)
TDO   : Pin11 (Busy)
SRST  : Pin2 (D0)
TRST  : Pin6 (D4)

(参见Wiggler的电路图,但最后的nSRST和nTRST可能不一定用到,并且在H-JTAG中的定义也不一样,TRST是Pin2,没有SRST)

H-JTAG里还有另外一种接法--STD,定义如下:
TMS   : Pin3 (D1)
TCK   : Pin2 (D0)
TDI   : Pin8 (D6)
TDO   : Pin13 (Select)
SRST  : N/A
TRST  : Pin4 (D2)


而S3C2410的烧写程序SJF2410用的是:
TCK   : Pin2 (D0)
TDI   : Pin3 (D1)
TMS   : Pin4 (D2)
TDO   : Pin11 (Busy)

这个可以在源代码中的jtag.h文件里看到。

除了DB25那边的Pin Assignment有多种方案,JTAG connector也有20pin, 14pin, 12pin, 10pin等几种标准。这里一块ARM9开发板配的DB25-JTAG转换板就十分好玩,上面也是只有一块244,但是有Wiggler, STD, S3C2410三个20pin接口。由于20pin connector的Pin Assignment是固定的,三个接口对应的是DB25那边的三种接法,因此开发板可以根据pc上运行的程序不同选择不同的接口来接。

20Pin Connector的定义如下(参考此图):
 Vcc      1  2 NC
 nTRST    3  4 GND
 TDI      5  6 GND
 TMS      7  8 GND
 TCK      9 10 GND
 GND     11 12 GND
 TDO     13 14 GND
 NRESET  15 16 GND
 NC      17 18 GND
 NC      19 20 GND


14Pin:
 nTRST  1   2 GND
 TDI    3   4 GND
 TDO    5   6 GND
 TMS    7   8 GND
 TCK    9  10 GND
 nSRST 11  12 n/a
 DINT  13  14 Vcc

(DINT pin is used to raise Debug Interrupt. Many chips has no this pin.)


12Pin:
 nTRST  1   2 GND
 TDI    3   4 GND
 TDO    5   6 GND
 TMS    7   8 GND
 TCK    9  10 GND
 nSRST 11  12 GND


10Pin:
 TCK    1   2 Vcc
 TDI    3   4 Vcc
 TDO    5   6 GND
 TMS    7   8 GND
 nTRST  9  10 GND



关于JTAG几个信号,在H-JTAG主页上提供了一个文档,里面有对此进行介绍:

……下面,让我们从TAP(Test Access Port)开始。
  TAP是一个通用的端口,通过TAP可以访问芯片提供的所有数据寄存器(DR)和指令寄存器(IR)。对整个TAP的控制是通过TAP Controller来完成的。TAP总共包括5个信号接口TCK、TMS、TDI、TDO和TRST :其中4个是输入信号接口和另外1个是输出信号接口。一般,我们见到的开发板上都有一个JTAG接口,该JTAG接口的主要信号接口就是这5个。下面,我先分别介绍这个5个接口信号及其作用。
Test Clock Input (TCK)
TCK为TAP的操作提供了一个独立的、基本的时钟信号,TAP的所有操作都是通过这个时钟信号来驱动的。TCK在IEEE 1149.1标准里是强制要求的。
Test Mode Selection Input (TMS)
TMS信号用来控制TAP状态机的转换。通过TMS信号,可以控制TAP在不同的状态间相互转换。TMS信号在TCK的上升沿有效。TMS在IEEE 1149.1标准里是强制要求的。
Test Data Input (TDI)
TDI是数据输入的接口。所有要输入到特定寄存器的数据都是通过TDI接口一位一位串行输入的(由TCK驱动)。TDI在IEEE 1149.1标准里是强制要求的。
Test Data Output (TDO)
TDO是数据输出的接口。所有要从特定的寄存器中输出的数据都是通过TDO接口一位一位串行输出的(由TCK驱动)。TDO在IEEE 1149.1标准里是强制要求的。
Test Reset Input (TRST)
TRST可以用来对TAP Controller进行复位(初始化)。不过这个信号接口在IEEE 1149.1标准里是可选的,并不是强制要求的。因为通过TMS也可以对TAP Controller进行复位(初始化)。

  事实上,通过TAP接口,对数据寄存器(DR)进行访问的一般过程是:
  1 通过指令寄存器(IR),选定一个需要访问的数据寄存器;
  2 把选定的数据寄存器连接到TDI和TDO之间;
  3 由TCK驱动,通过TDI,把需要的数据输入到选定的数据寄存器当中去;同时把选定的数据寄存器中的数据通过TDO读出来。


另外,可选信号nSRST的定义如下(见参考资料1):
nSRST is a "system reset" signal and acts like conventional "Reset' button.


参考资料:
[1] http://www.linux-mips.org/wiki/JTAG
[2] http://en.wikipedia.org/wiki/Jtag
[3] http://docwiki.gumstix.org/JTAG
[4] http://wiki.openwrt.org/OpenWrtDocs/Customizing/Hardware/JTAG_Cable
[5] http://www.bluewaternz.com/corporate/uni/unikit/jtag/