第五章 软件层之AGDI接口(2)

        上一章节我们已经了解了uVision2 IDE平台的大体布局和一些功能(包括下载程序、进入仿真、单步执行、停止运行等等),在这一章节中我们就来详细介绍uVision2提供的这些功能对应的AGDI接口函数。

        AGDI是Keil提供的一组API,里面包含了对上面说到的下载程序和仿真调试的所有接口函数,它是用来驱动在线调试器的。AGDI接口独立于处理器的体系结构,所以能很方便的实现驱动的开发并且带来很小的开销。我们通过该接口编写自己的目标驱动dll来连接调试器和Keil IDE。在工程中的AGDI文件中,所有以AG_开头的函数都需要在目标驱动dll中被定义,不过也可以是一个空函数,他们用于实现了调试器的各项功能。

接口函数功能描述
AG_Init()AGDI的初始化函数
AG_MemAtt()内存访问函数
AG_BpInfo()断点设置/重置/使能/失能/清除
AG_BreakFunc()断点访问函数

AG_GoStep()

运行/停止命令
AG_Serial()读/写窗口函数
AG_MemAcc()访问被调试的单片机的内存函数
AG_RegAcc()读/写单个寄存器的函数
AG_AllReg()读/写所有寄存器的函数
AG_HistFunc()追踪历史操作的函数

AG_Init() :AGDI的初始化,不管是下载程序还是进入仿真,Keil IDE一定会调用AG_Init这个函数很多次来初始化一些指针和参数,AG_Init的部分代码如下:


/*----------- AGDI Basic Functions -----------------*/
/*AGDI-Init Function*/
U32 _EXPO_ AG_Init (U16 nCode, void *vp)  {
  U32     nE;
  nE = 0;
  switch (nCode & 0xFF00)  {
    case AG_INITFEATURES:     // Initialize & start the target
      PlayDead = 0;           // clear some variables...
      //---We don't have special features here, so all variables are cleared.
      //---uVision2 will query these features lateron.
      //---Note: the 'supp' structure is defined in 'AGDI.H'
      supp.MemAccR  = 0;      // memory-access while running
      supp.RegAccR  = 0;      // register-access while running
      supp.hTrace   = 0;      // trace support
      supp.hCover   = 0;      // code coverage support
      supp.hPaLyze  = 0;      // Performance-Analyzer support
      supp.hMemMap  = 0;      // Memory-Map support
      supp.ResetR   = 0;      // Reset while running support
      //---Note: if InitTarget() fails, then set nE=1, else nE=0.
      //         if 1 is returned, then uVision will cancel using this driver
      FlashProg = 0; 
      InitMem();                 // init Cache memory
      bootflag = 1;
      nE       = InitTarget();   // Initialize your target...
      bootflag = 0;
      if (nE == 0)  {            // initialization was Ok.
        InitRegs();              // define register layout for RegWindow
      }

      if (nE == 0)  {            // everything is ok so far
        pCbFunc (AG_CB_EXECCMD, "U $\n");  // force disassemble @curPC
      }
      NumRecs = 0;                // clear 'number of trace records'
      break;

    case AG_INITITEM:             // init item
      switch (nCode & 0x00FF)  {
        case AG_INITMENU:         // init extension menu
          *((DYMENU **) vp) = (DYMENU *) Menu;
          break;
        case AG_INITEXTDLGUPD:    // init modeless extesion dlg update function
          *((UC8 **) vp) = (UC8 *) DlgUpdate;
          break;
        case AG_INITMHANDLEP:     // setup ptr to HWND of active modeless dlg
          pHwnd = (HWND *) vp;
          break;
        case AG_INITPHANDLEP:     // pointer to parent handle (MainFrame)
          hMfrm = (HWND) vp;
          break;
        case AG_INITINSTHANDLE:   // pointer to Agdi-instance handle
          hInst = (HMODULE) vp;
          break;
        case AG_INITBPHEAD:       // pointer to head of Bp-List
          pBhead = (AG_BP **) vp;
          break;
        case AG_INITCURPC:        // pointer to program counter
          pCURPC = (UL32 *) vp;
          break;
        case AG_INITDOEVENTS:     // DoEvents function pointer
        //--- this is no longer relevant due to uVision's threading.
          break;
        case AG_INITUSRMSG:       // Registered Message for SendMessage
          Uv2Msg = (DWORD) vp;    // (Serial-Window, TextOut messages)
          break;
        case AG_INITCALLBACK:     // pointer to callback function
          pCbFunc = (pCBF) vp;    // call-back function of s166
          break;
        case AG_INITFLASHLOAD:    // Prepare for Flash Download
          nE = InitProgrammer ();
          if (nE) break;
          nE = InitDevFlash ();   // Initialize Flash, Erase
          break;
        case AG_STARTFLASHLOAD:   // S8051 says 'Ready for Flash DownLoad'
          nE = FlashLoad();       // Flash-Download, write, verify
          break;
      }
      break;

    case AG_GETFEATURE:           // uVision2 want's details about features...
      switch (nCode & 0x00FF)  {
        case AG_F_MEMACCR:    nE = supp.MemAccR; break;
        case AG_F_REGACCR:    nE = supp.RegAccR; break;
        case AG_F_TRACE:      nE = supp.hTrace;  break;
        case AG_F_COVERAGE:   nE = supp.hCover;  break;
        case AG_F_PALYZE:     nE = supp.hPaLyze; break;
        case AG_F_MEMMAP:     nE = supp.hMemMap; break;
        case AG_F_RESETR:     nE = supp.ResetR;  break;
      }
      break;

    case AG_EXECITEM:             // execute various commands
      switch (nCode & 0x00FF)  {
        case AG_UNINIT:           // Clean up target system settings
          ExitProgrammer ();      // Stop Programmer
          PlayDead = 1;           // mark target as disconnected.
          CloseAllDlg();          // close all open dialogs
          StopTarget();           // shutdown target & communication
          WriteMonParms (pdbg->TargArgs);  // update argument string
          break;

        case AG_RESET:            // perform a reset on the target system
          if (PlayDead || hMfrm == NULL) break;  // target is disconnected
          ResetTarget();          // reset the target
          pCbFunc (AG_CB_EXECCMD, "U $\n");      // dasm $
          NumRecs = 0;            // clear 'number of trace records'
          break;
      }
      break;
  }

  if (PlayDead)  {       // driver is disconnected
    StopTarget();        // shut down driver
    PostMessage (hMfrm, Uv2Msg, MSG_UV2_TERMINATE, 0);  // unload this driver
  }

  return (nE);
}

        根据小编在开发的过程中发现Keil在下载程序和进入仿真这两个过程调用AG_Init时参数nCode的值和顺序均不同,两者的调用顺序分别为:

        在下载的过程中,AGDI会通过上面这些调用顺序分别调用函数 “InitProgramme()”、“InitDevFlash()”、“FlashLoad()” 这三个函数需要我们来实现的,主要是对目标单片机中的主控芯片进行程序的烧录的初始化和少些过程。

        在进入仿真的过程中,AGDI会通过上面这些调用顺序,调用 ResetTarget() 函数,这个函数和我们后面点击程序Reset时候调用的函数接口是同一个,所以在 ResetTarget() 函数里面要做好区分这两者的标志。

        AG_BpInfo() :  这个接口是做断点的设置/重置/使能/失能/清除的操作。当我们在要调试的工程中设置断点或者清除断点的时候均会调用到这个接口,并且nCode的参数会根据我们的操作进行赋值。


U32 _EXPO_ AG_BpInfo (U16 nCode, void *vp)  {
  U32     nA, nAdr;
  U16    *pB;
  AG_BP  *pK;

  if (PlayDead) return (0);
  switch (nCode)  {
    case AG_BPDISALL:                  // disable all Exec-Bp's
    case AG_BPKILLALL:                 // kill all Exec-Bp's
      break;
    default:                           // need attribute pointer anyway, set it up here.
      nAdr = ((GADR *) vp)->Adr;       // the referred address
      pB   = MGetAttr (nAdr);          // get attribute location for 'nAdr'
      if (!pB) return (0x80000000);    // failed: unmapped address
      break;
  }

  nA = 0;
  switch (nCode)  {                    // Function code
    case AG_BPQUERY:                   // Query Break
    case AG_BPEXQUERY:                 // Query for 'executed' attribute
      nA = (UL32) (*pB & __BPQX);      // Attributes are similar to uVision
      break;

    case AG_BPENABLE:                               // enable breakpoint
      if (*pB & AG_ATR_BPDIS)  {                    // is Bp disabled ?
        *pB = (*pB & ~AG_ATR_BPDIS) | AG_ATR_BREAK; // enable it
      }
      break;

    case AG_BPDISABLE:                              // disable breakpoint
      if (*pB & AG_ATR_BREAK)  {                    // is Bp enabled ?
        *pB = (*pB & ~AG_ATR_BREAK) | AG_ATR_BPDIS; // disable it
        break;
      }
      break;

    case AG_BPKILL:                                 // kill breakpoint
      *pB = *pB & ~(AG_ATR_BREAK | AG_ATR_BPDIS);
      break;

    case AG_BPSET:                                  // Set breakpoint
      *pB = (*pB & ~AG_ATR_BPDIS) | AG_ATR_BREAK;
      break;

    case AG_BPDISALL:                  // disable all Bp's
      pK = *pBhead;                    // head of breakpoint list
      for ( ; pK ; pK = pK->next )  {
        if (pK->type != AG_ABREAK || !pK->enabled)  {
          continue;
        }
        ++nA;                          // count number of changed Bp's
        pB = MGetAttr (pK->Adr);             // get attribute location
        if (pB && (*pB & AG_ATR_BREAK))  {   // is Bp enabled ?
          *pB = (*pB & ~AG_ATR_BREAK) | AG_ATR_BPDIS; // disable it
        }
      }
      break;

    case AG_BPKILLALL:                 // kill all Bp's
      pK = *pBhead;                    // head of breakpoint list
      for ( ; pK ; pK = pK->next )  {
        if (pK->type != AG_ABREAK) continue;
        ++nA;                          // count number of changed Bp's
        pB = MGetAttr (pK->Adr);       // get attribute location
        if (pB)  {
          *pB = *pB & ~(AG_ATR_BREAK | AG_ATR_BPDIS);
        }
      }
      break;
  }

  if (PlayDead == 1)  {
    StopTarget();
    PostMessage (hMfrm, Uv2Msg, MSG_UV2_TERMINATE, 0);
  }
  return (nA);
}

        AG_GoStep()  : 这个接口主要是实现单步执行、多步执行、运行断点、跳出函数、单行运行、运行到光标处、停止调试等操作。例如当我们点击单步执行的时候,这个接口中的nCode参数就会设置为AG_NSTEP,并且nSteps参数会被设置为当前指令的条数(也就是当前C语言语句编译成汇编语言的指令条数)。


/*
 * Go/Step/Stop commands
 */

_EXPO_ U32 AG_GoStep (U16 nCode, U32 nSteps, GADR *pA)  {
  U32     nE;

  if (PlayDead) return (0);           // driver is disconnected.

  nE = 0;                             // clear error code
  switch (nCode)  {
    case AG_STOPRUN:                  // Stop Go/Step.
      StopRun = 1;
      nE = StopExec();                // nE:  1=Stopped, 0=executing
      if (nE == 1) iRun = 0;          // stopped.
      if (!iRun)  {
        Invalidate();                 // registers, caches, etc.
      }
      NumRecs = 0;                    // clear 'number of trace records'
      break;

    case AG_NSTEP:                    // execute 'nSteps' instruction steps
      iRun = 1;                       // 'executing'
      for ( ; nSteps != 0 ; --nSteps )  {
        if (StopRun) break;           // Stop-Button was pressed
        if (Step() != 0x01) break;    // 0x01 means 'Ok.'
      }
      StopRun = 0;                    // clear Stop-Button flag.
      Invalidate();                   // registers, caches, etc.
      iRun = 0;                       // clear 'executing' flag
      NumRecs = 0;                    // clear 'number of trace records'
      break;

    case AG_GOTILADR:                 // run til 'pA->Adr' or some Bp,
      iRun = 1;                       // whichever comes first
      GoUntil (pA->Adr);
      StopRun = 0;
      Invalidate();                   // registers, caches, etc.
      iRun = 0;                       // clear 'executing' flag
      NumRecs = 0;                    // clear 'number of trace records'
      break;

    case AG_GOFORBRK:                 // run forever or till some Bp reached.
      iRun = 1;
      GoUntil (0xFFFFFFFF);           // means 'go forever'
      StopRun = 0;
      Invalidate();                   // registers, caches, etc.
      iRun = 0;                       // clear 'executing' flag
      NumRecs = 0;                    // clear 'number of trace records'
      break;
  }

  if (PlayDead)  {                    // target not connected
    StopTarget();                     // shut it down
    PostMessage (hMfrm, Uv2Msg, MSG_UV2_TERMINATE, 0); // terminate ourselves
  }
  else  {
    GetRegs();                        // get target registers
    *pCURPC = REG51.nPC;              // let uVision2 know about PC...
  }
  return (nE);
}

        AG_MemAcc() : 这个接口实现了我们在调试的过程中读取/修改某个变量的值,或者读取整个数据存储区的数据。从代码中可以看到,在读取或者写入的函数参数都是三个,分别是nA、pB、nMany,其中nA指的是要读取/写入的变量的地址,pB指的是要存放读取变量的空间(或者修改该变量的新的数值),nMany指的该变量数值的字节数。例如,当我们要读取代码中变量 i 的值,可以将鼠标移动到变量 i 的位置,这时候其实就已经触发到这个接口了,这个接口会将变量 i 的地址nA和这个变量的字节数nMany(假如变量 i 定义为UNIT32的话,就是四个字节,这时候nMany就等于4),然后将读取后的数值放置到pB管道中,Keil会读取这管道显示到界面中。

/*
 * Access target memory
 */

U32 _EXPO_ AG_MemAcc (U16 nCode, UC8 *pB, GADR *pA, UL32 nMany)  {
  U16     nErr;
  UL32      nA;

  if (iRun && !supp.MemAccR)  {     // currently running, can't access.
    return (AG_NOACCESS);           // error: can't access register
  }
  if (PlayDead)  {                  // driver disconnected.
    return (AG_NOACCESS);
  }

  nErr = 0;
  if (hMfrm == NULL) return (nErr);

  nA = pA->Adr;
  switch (nCode)  {
    case AG_READ:                   // need 'read' permission
      pA->ErrAdr = ReadMem (nA, pB, nMany);
      if (pA->ErrAdr) nErr = AG_RDFAILED;
      break;

    case AG_WRITE:                  // need 'write' permission
      pA->ErrAdr = WriteMem (nA, pB, nMany);
      if (pA->ErrAdr) nErr = AG_WRFAILED;
      break;
                                    // used for Program download
    case AG_WROPC:                  // need 'Read/Execute' permissions
      nA |= (amCODE << 24);
      pA->ErrAdr = WriteMem (nA, pB, nMany);
      if (pA->ErrAdr) nErr = AG_WRFAILED;
      break;
                                    // used for disassembly etc.
    case AG_RDOPC:                  // need 'Read/Execute' permissions
      nA |= (amCODE << 24);
      pA->ErrAdr = ReadMem (nA, pB, nMany);
      if (pA->ErrAdr) nErr = AG_RDFAILED;
      break;

    default:
      nErr = AG_INVALOP;            // invalid Operation
      break;
  }

  if (PlayDead == 1) {   // disconnected...
    StopTarget();        // shut down driver
    PostMessage (hMfrm, Uv2Msg, MSG_UV2_TERMINATE, 0);
  }
  return (nErr);
}

        AG_RegAcc() : 这个接口是读取单片机芯片的内置寄存器的数值,包括R0~R7、psw等等。

/*
 * Read/Write a single Register
 */

U32 _EXPO_ AG_RegAcc (U16 nCode, U32 nReg, GVAL *pV)  {
  U16    nErr;

  if (iRun && !supp.RegAccR)  {     // currently running, can't access.
    return (AG_NOACCESS);           // error: can't access register
  }
  if (PlayDead) return (AG_NOACCESS);  // driver is disconnected.

  nErr = 0;
  switch (nCode)  {                 // which Opcode
    case AG_READ:                   // read register
      GetRegs();                    // make sure REG51 is up to date
      switch (nReg)  {
        case nnR0: case nnR1: case nnR2: case nnR3:
        case nnR4: case nnR5: case nnR6: case nnR7:
          pV->uc = REG51.Rn [nReg & 0x07];
          break;
        case nrA:
          pV->uc = REG51.acc;
          break;
        case nrDPTR:
          pV->u16 = (((WORD16) REG51.dph) << 8) | (WORD16) REG51.dpl;
          break;
        case mPC:
          pV->u32 = REG51.nPC;      // Note: requires 'amCODE << 24' selector.
          break;
      }
      break;

    case AG_WRITE:
      switch (nReg)  {
        case nnR0: case nnR1: case nnR2: case nnR3:
        case nnR4: case nnR5: case nnR6: case nnR7:
          REG51.Rn [nReg & 0x07] = pV->uc;
x:        SetRegs (&REG51);
          break;
        case nrA:
          REG51.acc = pV->uc;
          goto x;
        case nrDPTR:
          REG51.dpl = (BYTE) (pV->u16 & 0xFF);
          REG51.dph = (BYTE) ((pV->u16 >> 8) & 0xFF);
          goto x;
        case mPC:
          curPC = pV->u32;
          WritePC (curPC);          // to target
          break;
      }
      break;

    default:
      nErr = AG_INVALOP;            // invalid Operation
      break;
  }
  if (PlayDead == 1)  {
    StopTarget();
    PostMessage (hMfrm, Uv2Msg, MSG_UV2_TERMINATE, 0);
  }
  return (nErr);
}

        上面讲的就是AGDI常用的接口啦。

        OK啦,这一章就介绍到这里了~~

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: coocox-agdi.dll是一个动态链接库文件,它是CoIDE集成开发环境中的一个重要组成部分。CoIDE是一个开源的多功能软件开发工具,用于嵌入式系统的开发。 coocox-agdi.dll文件的功能是提供与调试器相关的功能,它支持多种芯片的调试和仿真。通过使用这个DLL文件,开发人员可以连接和调试各种硬件设备,如微控制器、微处理器和其他嵌入式系统。 在CoIDE中,coocox-agdi.dll文件会自动加载,它能够与系统的硬件调试接口进行交互,帮助开发人员进行程序的调试和验证。通过调用其中的函数和方法,开发人员可以控制硬件的运行状态、读取和写入寄存器的值、单步执行程序等。 对于嵌入式系统开发人员来说,coocox-agdi.dll文件是非常重要的,它提供了调试和验证硬件功能的接口,帮助开发人员在开发过程中快速定位和解决问题。同时,它还提供了一些高级功能,如跟踪指令执行流、断点设置、变量监视等,使得调试工作更加高效和便捷。 总之,coocox-agdi.dll文件是CoIDE中重要的组成部分,它提供了与硬件调试相关的功能接口,帮助开发人员进行嵌入式系统的开发和调试工作。 ### 回答2: coocox-agdi.dll是CooCox公司开发的一个动态链接库文件,用于与CooCox IDE集成的调试器驱动程序之间的交互。CooCox IDE是一款专为嵌入式系统开发而设计的集成开发环境,而coocox-agdi.dll则是其中重要的一部分。 coocox-agdi.dll提供了一系列的函数和接口,用于实现与调试器的通信。它可以解析和处理调试信息,将程序运行过程中的变量状态、寄存器值等信息提供给开发者进行调试和分析。通过与coocox-agdi.dll的交互,开发者可以在CooCox IDE中实现单步调试、断点设置等常用调试功能,方便开发者进行代码调试和错误排查。 在使用CooCox IDE进行嵌入式软件开发时,coocox-agdi.dll是不可或缺的组件之一。它不仅具备提供调试功能的能力,还能够与其他组件和插件进行协同工作,为开发者提供一个完整、高效的开发环境。 总的来说,coocox-agdi.dll在CooCox IDE中扮演着重要的角色,它是调试器驱动程序与IDE之间的桥梁,为开发者提供了强大的调试能力,帮助开发者提高开发效率,减少错误。它的存在使得嵌入式开发更加方便和可靠。 ### 回答3: coocox-agdi.dll 是一个动态链接库文件,常见于 CooCox 软件开发环境中。CooCox 是一个嵌入式系统开发工具,常用于 ARM Cortex-M系列微控制器的开发。该软件提供一个集成开发环境,包括编译器、调试器和仿真器等工具,用于嵌入式系统的开发和调试。 coocox-agdi.dll 是其中一个重要的库文件,它包含了与调试相关的函数和资源。通过这个库文件,应用程序可以与硬件之间建立连接,实现对目标设备的调试和仿真。coocox-agdi.dll 提供了一系列的接口函数,用于初始化调试器、控制目标设备的运行和读取其状态等操作。程序员可以根据需要调用这些函数,完成特定的调试任务。 值得注意的是,coocox-agdi.dll 只是其中一个库文件,它依赖于其他许多库文件和程序组件,一起构成 CooCox 软件开发环境。使用该库文件进行开发和调试时,需要确保所有相关的软件和驱动程序都正确安装并配置好。此外,确保库文件的版本与其他组件的版本兼容,以确保软件开发的稳定性和正确性。 总之,coocox-agdi.dll 是 CooCox 软件开发环境中的一个重要的动态链接库文件,用于嵌入式系统的调试和仿真。它提供了与硬件交互的接口函数,帮助开发人员实现对目标设备的控制和状态读取等操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三贝勒文子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值