通过MCU/ARM/CPU在线加载 Lattice CPLD/FPGA-Lattice-莱迪斯论坛-FPGA CPLD-ChipDebug

通过MCU/ARM/CPU在线加载 Lattice CPLD/FPGA

LATTICE-CPLD/FPGA的在线加载程序包含7个文件,程序在安装目录下
1)debug.h
定义状态机操作中各个命令的字符串
2)hardware.h
定义硬件资源
3)hardware.c
和硬件操作相关的代码
4)ispvm_ui.c
和用户接口相关的代码
5)ivm_core.c
JTAG状态机操作代码
6)vmopcode.h
定义状态机操作中各个命令
7)IEEE1532.c
用于CRC校验

下图是这个代码包在我电脑中的位置。

 

注意在新版的diamond安装目录下没有只有4个文件,是因为有一些文件内的代码移到ivm_core.c里面,但仍然基本上可以照搬本文进行操作。

因为这套代码是用于PC机的所以,移植到我们的系统中必须作些改动,我们需要改动的代码主要有:
1)hardware.h
在这里定义我们使用的硬件管脚资源。
2)hardware.c
修改writePort(),readPort,ispVMDelay()三个函数
修改包含的头文件
3)ispvm_ui.c
修改接口函数,可以自己封装ispVM()函数,但是建议修改原有的main()函数
4)vmopcode.h
将READ,LOCAL两个宏定义改个名字。

1. 文件的修改

1.1 修改hardware.h

CPLD/FPGA的加载使用5根信号线,分别是TDI,TDO,TMS,TCK和CE。在hardware.h中的定义的管脚有7根分别是pinTDI,pinTCK,pinTMS,pinENABLE,pinTRST,pinCE, pinTDO。我们使用pinTDI,pinTCK,pinTMS,pinCE, pinTDO这5个。

需要注意的是pinTDI,pinTCK,pinTMS,pinCE, pinTDO只是用来标记管脚的名字,不是一定要把他们定义成PD10等,当然你也可以这样做。

所以这里有两种方案:
1)管脚名定义和实际管脚一致

#define    pinTDI       PD10
#define    pinTCK       PD8
#define    pinTMS       PD9
#define    pinCE        PD4
#define    pinTDO       PD11

2)管脚名和实际管脚分开定义

#define pinTDI       (1<<0)     
#define pinTCK       (1<<1)
#define pinTMS       (1<<2)
#define pinCE        (1<<3)
#define pinTDO       (1<<4)      
#define PIN_TDI       PD10
#define PIN_TCK       PD8
#define PIN_TMS       PD9
#define PIN_CE        PD4
#define PIN_TDO       PD11

定义不同,writePort和readPort的实现不同。

1.2 修改hardware.c

该文件封装了对硬件的操作,主要集中在三个函数上writePort,readPort,ispVMDelay。
writePort是写端口操作,有两个参数第一个是管脚,第二个是电平。需要注意的在V8.1下一次写操作可能操作多个管脚。这就是为何上面对管脚的定义是
#define pinTMS (1<<2)
而不是
#define pinTMS 3

在V10.0下好象没有一次操作多个管脚。第二个参数的值为(0x00,0x01)。
readPort是读端口操作,没有参数,只要对TDO的读取。
ispVMDelay是延时函数,有一个参数–延时的时间。需要注意的是该参数的高两位是量度(在V8.1下是最高位),当最高两位为0B11时,表示参数是毫秒,当最高两位为0B00时,表示参数是微秒。在函数中的延时以毫秒为单位,不到一毫秒,延时一毫秒。
hardware.c中包含了许多头文件,其中有些是windows操作系统的头文件,我们必须将其替换成vxworks的头文件

/*
#include <windows.h>
#include <mmsystem.h>
#include <dos.h>
#include <malloc.h>
#include <conio.h>
*/
#include <vxworks.h>
#include <loglib.h>

1.3 修改ispvm_ui.c

在这个接口文件中,提供了一个加载函数ispVM(char filename ),但是不提倡使用,因为该函数中没有提供CRC校验。在该文件中还有一个main(int argc, char argv[])建议修改该函数,作为我们的在线加载函数,因为其中提供了IEEE1532标准的CRC校验。

1.4 修改vmopcode.h

在该文件的宏定义中有两个宏定义READ,LOCAL这两个宏定义在编译时发现和vxworks的定义冲突,所以必须将这两个宏定义的名字修改,建议改为

#define LOCALL
#define READD

1.5 修改函数返回值

char  ispVM(char *);
char  ispVMShift(char Code);
char  ispVMAmble(char Code);
char  ispVMLoop(unsigned short loop_cnt);

这几个函数的返回值类型为char。在实际测试中发现当文件不存在,文件错等异常测试中,都打印出成功信息。经过代码分析,在这些函数中当返回值为0时成功,当失败时返回代表失败的负数(如-1,代表加载文件校验错),但是函数返回后这些数变成正数(如255)。所以打印出成功信息。

所以将这几个函数的返回值类型改为int,且将

 

该问题解决,可以正确检查
1)CRC校验错
2)找不到文件
3)文件类型错
4)文件错
5)参数错
五种错误。

代码中和延时相关的部分:
修改后的代码:

 

说明:
这个函数原来应该是采用for循环延时,我们修改为对PPC的TIMEBASE计数来延时。输入参数是1,就是1各微秒 ;

使用情况:
在原来代码的以下地方使用:
a. 在文件IVM_Hardware.c中的以下函数:

 

插入1微秒延时。

b. 在IVM_CORE.C中的以下函数:

/****************************************************************************
                     ispVM Shift                            
 Perform the function of SIR, SDR and XSDR. It is to shift instruction or
 Data into TDI and/or out of TDO.  
 global:
    DataSize----------The size (bits) of the data or instruction to process.                  

 Input                                                          
     Code---------------SIR,SDR or XSDR      
 Return                                                         
     rcode--------------pass or fail

*****************************************************************************/
int ispVMShift(char Code)
{
 int i;
 int j;
 int rcode;

 rcode=0;
 DataSize = ispVMDataSize();
#ifdef DEBUG
 printf("bits size=%d\n",DataSize);
#endif

 DataType &= ~(SIR_DATA+EXPRESS+SDR_DATA);   /*clear the flags first*/
 switch (Code) {
    case SIR:   /*shift instruction stream into devices*/
                DataType |= SIR_DATA;  /*Mark instruction shift to be performed*/
                if (FlowControl&NOOP) 
                    break;  /* no action shall take place*/
                if (FlowControl&CASCADE) {/*if no cascade*/
                    ispVMStateMachine(SHIFTIR);
                }
                else {
                    ispVMStateMachine(IRPAUSE);
                    ispVMStateMachine(SHIFTIR);
                    if (HeadIR > 0){ 
                        ispVMBypass(HIR,HeadIR);
                        sclock();
                    }
                }
                break;
    case XSDR:  DataType |= EXPRESS; /*mark simultaneous in and out*/
    case SDR:   DataType |= SDR_DATA; /*mark data shift to be performed*/
            /*Scan address or program data into devices*/
                /*check compression flag of the current VME file*/
                if (FlowControl&NOOP) 
                    break;  /*no action on the device*/
                /*Bypass other devices when appropriate*/
                if (CurState != DRPAUSE) { 
                    if (FlowControl&CASCADE) { /*if no cascade*/
                        /*ready the device to receive data stream*/
                        ispVMStateMachine(SHIFTDR);
                    }
                    else {
                        ispVMStateMachine(DRPAUSE);
                        ispVMStateMachine(SHIFTDR);
                        if(HeadDR > 0){
                            ispVMBypass(HDR,HeadDR);
                            sclock();
                        }

                    }
                }
                else {
                    if(HeadDR > 0){
                        ispVMBypass(HDR,HeadDR);
                        sclock();
                    }
                    ispVMStateMachine(SHIFTDR);
                }
                /*Data is shiftable if DataSize is less than MaxSize*/
                if (DataSize < MaxSize) {
                    rightShift = 1;
                }
                break;
    default:    /*error in file */
                return (-4);
    }

    /*fetch and keep the data stream*/
    rcode=ispVMDataCode();

    if (rcode != 0) 
        return (-4);   /*file has error*/

    /*Bypass other devices when appropriate*/
    if (FlowControl&NOOP) {} /*don't take the action on the devices*/
    else {/*send the instruction or data to the devices*/
        if (DataType&TDO_DATA || DataType&READ_DATA) {
            rcode = ispVMRead(DataSize);
            /* if vendor is XILINX, continue reading until pass */
            if (rcode == -1 && vendor == XILINX) {
                for(j = 0; j < 30; j++){
                    rcode = ispVMRead(DataSize);
                    if(!rcode)
                        break;
                    else {
                        ispVMStateMachine(DRPAUSE); /*Always DRPAUSE*/
                        /*Bypass other devices when appropriate*/
                        ispVMBypass(TDR,TailDR);
                        ispVMStateMachine(End_DR);
                        ispVMStateMachine(IDLE);
                        ispVMDelay(1);                      //延时1us(我加的说明)
                    }
                }
            }
        }
        else {           /*TDI only*/
            rcode = ispVMSend(DataSize);
        }
    }

 if (FlowControl&SKIPERROR) {  /*ignore the result*/
     rcode = 0;                /*make it pass always*/
     }
 /*transfer the input data to the output buffer for the next verify*/
 if (DataType&EXPRESS) {
     for (i=0; i<DataSize/8+1; i++)
         OutData[i] = InData[i];
 }
 /*No further action on the device*/
 if (FlowControl&NOOP) return (rcode); 

 switch(Code) {
    case SIR:  /*Bypass other devices when appropriate*/
               if (FlowControl&CASCADE) { /*if no cascade*/
                   ispVMStateMachine(End_IR);
               }
               else {
                   if (TailIR > 0) {
                       sclock();
                       ispVMBypass(TIR,TailIR);  /*shift trailer*/
                   }
                   ispVMStateMachine(End_IR);
               }
               break;
    case XSDR:
    case SDR:  
               /*Bypass other devices when appropriate*/
               if (FlowControl&CASCADE) {  /*default is no cascade*/
                   /*ispVMStateMachine(SHIFTDR);*/
               }
               else {
                   if (TailDR > 0) {
                       sclock();
                       ispVMBypass(TDR,TailDR);  /*shift trailer if no cascade*/
                   }
                   ispVMStateMachine(End_DR);
               }
               break;
    default:   break;
    }

 return (rcode); 
}

c. IVM_CORE.C中的以下函数:

/****************************************************************************
                     ispVMCode                                
 This is the core of ispVM Embedded. The ispVM opcodes are extracted and
 interpreted in this module. The ispVM opcodes supported here are only
 high level ispVM opcodes. High level opcodes simplify users' task in
 creating the VME files. For example:
 To scan an instruction into the targeted device(s), the VME program is:
 SVF:  SIR 5 TDI (0x0A);
 VME:  0x01,0x00,0x05,0x03,0x50,0x00;
       SIR opcode = 0x01;
       size = 0x00, 0x05;
       TDI opcode = 0x03;
       data = 0x50 which is reverse of 0x0A;
       ENDDATA opcode = 0x00;
 The high level opcode is splitted into multiple low level tasks by the ispVM
 Embedded:
  task 1: Fetch and keep all the operands, size and data stream etc.
          Allocate memory if necessary to keep the operands.
  task 2: Move the BSCAN state of the device to IRPAUSE.
  task 3: Put the leading and trailing devices into BYPASS mode.
  task 4: Move the BSCAN state machine to Shift-IR state.
  task 5: Shift the data stream into the target device(s);
  task 6: Move the BSCAN state machine to IRPAUSE.
  task 7: Move the BSCAN state machine to state as specified by ENDDR opcode.
  task 8: Put the leading and trailing devices into BYPASS mode.
 If low level opcodes are used instead, each task will require an opcode.
 This will go against the objective of having a small VME file size and
 fast programming time.
 Return                       
 Global var:                            
  compression --read instruction without compression read data with
                compression  
  tdodata     --true if TDO opcode is detected to indicate reading is
                necessary
  express     --true if EXPRESS SDR(XSDR) token is detected.
                XSDR will be carried out with Input data transferred to
                Output data buffer for next verify against. The XTDO opcode
                does not have data. The effect is to reduce the VME file
                size by half.                                
  DataSize    --the number of bits of data to be processed   
*****************************************************************************/
int ispVMCode()
{
 int repeatsize;
 char xch;
 int  rcode;
#ifdef DEBUG
 short int row = 0;
 int i;
#endif
 rcode = 0;

 while ((xch=GetByte()) >=0 ) { /*all opcode except ENDFILE are all positive*/
#ifdef DEBUG
        row++;
                for (i=0; i<opcode_cnt; i++)
                    if (ispVMOpcodes[i].token==xch) break;
                printf("row =%d opcode = %s\n", row, ispVMOpcodes[i].text);

#endif

#ifdef SILENT
 FlowControl |= NOOP;  /*nullified all actions*/
#endif

        switch (xch) {
          case STATE: /*step BSCAN state machine to specified state*/
                      ispVMStateMachine(GetByte());
                      break;
          case SIR:   /*shift instruction stream into devices*/
          case SDR:   /*shift data stream into devices*/
          case XSDR:  
#ifdef SHIFT
 FlowControl =~NOOP;  /*force a shift to happen only*/
#endif

                      rcode = ispVMShift(xch);
#ifdef SHIFT
 FlowControl |= NOOP;  /*resume nullification*/
#endif

#ifndef TEST||DEBUG
                      if (rcode != 0) 
                          return (rcode);
#endif
                      break;
          case WAIT:  /*opcode to wait for specified time in us or ms*/      
                      ispVMDelay(ispVMDataSize());                 //根据长度延时(我加的说明)
                      break;
          case TCK:   /*pulse TCK signal the specified time*/
                      ispVMClocks(ispVMDataSize());
                      break;
          case ENDDR: /*modify the BSCAN state after SDR opcode*/
                      End_DR = GetByte();
                      break;
          case ENDIR: /*modify the BSCAN state after SIR opcode*/
                      End_IR = GetByte();
                      break;
          case HIR:   /*modify the IR length of lead devices*/
          case TIR:   /*modify the IR length of the trailing devices*/
          case HDR:   /*modify the DATA length of the lead devices*/
          case TDR:   /*modify the DATA length of the trailing devices*/
                      if (ReturnCRC32()) {
                            /* print and re-initialize data CRC if
                            more than one device */
                            printf("data CRC: 0x%X\n", ReturnCRC32());
                            InitCRC32();
                      }
                      rcode = ispVMAmble(xch);
                      if (rcode != 0)
                          return (rcode);
                      break;
          case MEM:   /*The maximum RAM required for current VME file*/
                      MaxSize = ispVMDataSize();
                      break;
          case VENDOR:
                      xch = GetByte();
                      switch (xch) {
                      case LATTICE:
                          vendor = LATTICE;
                          break;
                      case ALTERA:
                          vendor = ALTERA;
                          break;
                      case XILINX:
                          vendor = XILINX;
                          break;
                      default:
                          break;
                      }
                      break;
/*8/23/01 ht add to support continue if verify fail*/
          case SETFLOW:  /*Set the continue if fail flag*/
                      FlowControl |= ispVMDataSize();
                      break;
          case RESETFLOW: /*Clear the continue if fail flag*/
                      FlowControl &= ~(ispVMDataSize());
                      break;
          case HEAP: /*the size of HEAP memory to store loops*/
                      rcode = GetByte();
                      if (rcode != SECUREHEAP) {
                          return -4;
                      }

                      HEAPSize = ispVMDataSize();  /*HEAP size in bytes*/
                      ispVMMemManager(HEAP,HEAPSize); /*get memory*/
                      break;               
          case REPEAT:   /*the begin of a monolithic loop*/
                      RepeatLoops = 0;
                      repeatsize = ispVMDataSize();
                      rcode = ispVMLoop(repeatsize);
#ifndef TEST||DEBUG
                      if (rcode != 0) return (rcode);
#endif
                      break;
          case ENDLOOP: 
                      return (rcode);  /*force a return*/
          case ENDVME: 
          case ENDFILE:  /*reach end of the current VME file*/ 
                      return(rcode);    /*return the result*/
          case SHR:   FlowControl |= SHIFTRIGHT;
                      OPCount = RepeatLoops * GetByte();
                      break;
          case SHL:   FlowControl |= SHIFTLEFT;
                      OPCount = RepeatLoops * GetByte();
                      break;    
          case FREQUENCY:
                Frequency = ispVMDataSize();
                break;
          default:    /*invalid opcode encountered*/
#ifdef TEST||DEBUG
                      printf("Illegal opcode (%02X)!\n",xch);
#endif
                      return -4;
          }
       }

   if ((xch < 0)&&(xch!=(char)ENDFILE))  
       return (-4); 
   else 
       return (rcode);        
}

上述几处都应是原来lattice的代码中存在,我们未进行修改。

请登录后发表评论