硬件设备 之一 详解 JTAG、SWD 接口、软 / 硬件断点、OpenOCD、J-link

news2024/9/21 22:36:36

  JTAG 和 SWD 在嵌入式开发中可以说是随处可见,他们通常被用来配合 J-Link 、ULINK、ST-LINK 等仿真器在线调试嵌入式程序。此外,还有飞思卡尔芯片中的 Background debug mode(BDM) 接口,Atmel 芯片中的 debugWIRE ;Nexus 5001 论坛制定的全球嵌入式处理器调试接口标准 IEEE-ISTO 5001。

JTAG

  JTAG 这个名字是由该标准的制定者 —— 联合测试行动小组(Joint Test Action Group)的名字缩写而来。其相关标准于 1990 年标准化为 IEEE Std. 1149.1-1990(该标准的全称是 Test Access Port and Boundary-Scan Architecture(测试访问端口和边界扫描架构))。
在这里插入图片描述

JTAG 是来自主要制造商的工程师团队的一个花哨的名字,他们坐在一起,提出了我们现在称为 JTAG 的标准。

边界扫描

  JTAG 制定之初是采用边界扫描技术的一种测试印刷电路板或集成电路内子模块上的互连(电线)的方法。 边界扫描被广泛用作观察集成电路引脚状态、测量电压或分析集成电路内部子模块的调试方法。在电路板上的很多芯片可以将他们的 JTAG 引脚通过 Daisy Chain 的方式连接在一起。
在这里插入图片描述
  边界扫描(Boundary-Scan)技术的基本思想是在靠近芯片的输入/输出引脚上增加一个移位寄存器单元,也就是边界扫描寄存器(Boundary-Scan Register)。当芯片处于调试状态时,边界扫描寄存器可以将芯片和外围的输入/输出隔离开来。通过边界扫描寄存器单元,可以实现对芯片输入/输出信号的观察和控制。
在这里插入图片描述
  现在,越来越多的器件采用 BGA(球栅阵列)封装。电路板上的每个 BGA 器件都对可以使用传统钉床或飞针机完成的测试施加了严格的限制。JTAG 则在球栅阵列(BGA)芯片的生产测试中提供了简单的方法,因此,边界扫描也被认为是 JTAG 的代名词。
在这里插入图片描述

调试

  JTAG 成立的主要目的是为了帮助电子设备的生产和测试,而不是实际上为软件调试制定标准!但随着时间的推移,芯片制造商发现 JTAG 集成到芯片内部就可以辅助芯片软件调试!如今,JTAG 被用作访问集成电路子模块的主要手段,使其成为调试嵌入式系统的基本机制。
在这里插入图片描述
  详细的调试协议(定义如何通过 JTAG 接口读取边界扫描寄存器)由架构厂商定义,例如 ARM 在 《ARM® Debug Interface v5》规范中给出了详细介绍 DP;RISC-V 则在 《RISC-V Debug Specification》中有详细的描述 DMI。
在这里插入图片描述

固件烧录

  JTAG 允许器件编程器硬件将数据传输到内部非易失性器件存储器(例如 CPLD,闪存),目前,所有 FPGA 和 CPLD 包括我们常用的 SoC、MCU 都使用 JTAG 来提供对其编程功能的访问。
在这里插入图片描述
  注意,固件烧录可以根据存储介质分为 RAM 烧录和 ROM 烧录。其中,RAM 烧录可以直接写,而 ROM 烧录则需要特定的烧写算法(通常做法是(例如,Keil),先将烧写算法写入到 RAM,然后运行 RAM 中的程序,调试器与 RAM 中的程序通信,实现烧录)。
在这里插入图片描述

TAP

  最初的 JTAG 标准 IEEE 1149.1 定义了 5 个引脚,这 5 个引脚统称为 Test Access Port(TAP)。JTAG 本身无固定电压,由目标板和目标芯片的 IO 供电电压决定,必须保证 JTAG 信号线与连接的芯片电压相同。

  • TCK: Test Clock,具有一个内部弱下拉电阻。TCK 为 TAP 的操作提供了一个独立的、基本的时钟信号,TAP 的所有操作都是通过这个时钟信号来驱动的。
  • TMS: Test Mode Select,具有内部弱上拉电阻。TMS 信号用来控制TAP状态机的转换,在 TCK 的上升沿有效。通过 TMS 信号,可以控制 TAP 在不同的状态间相互转换。
  • TDI: Test Data-In,具有内部弱上拉电阻。TDI 是数据输入的接口。所有要输入到特定寄存器的数据都是通过 TDI 接口一位一位串行输入的(由 TCK 驱动)。
  • TDO: Test Data-out。TDO 是数据输出的接口。所有要从特定的寄存器中输出的数据都是通过 TDO 接口一位一位串行输出的(由 TCK 驱动)。
  • TRST: Test Reset (Optional),具有内部弱上拉电阻。TRST 可以用来对 TAP Controller 进行复位(初始化)。因为 TRST 是可选的,所以有四线 JTAG 与五线 JTAG 之分。

IEEE-1149.7 标准定义的 compact JTAG(cJTAG)则减少了引脚数,只定义了 2 个引脚,可以采用星形拓扑结构连接:

  • TMSC: Test Serial Data
  • TCKS: Test Clock

以上仅仅是信号线,除此之外还可能有一些其他引脚

  • VTREF: 接口信号电平参考电压一般直接连接 Vsupply。这个可以用来确定 JTAG 接口使用的逻辑电平!我们常用的 J-Link、ULINK 等都可以由 5V 电压供电,然后其内部则可以转换输出 1.8V ~ 5V 从而直接给芯片供电。
  • System Reset ( nSRST): 可选项,与目标板上的系统复位信号相连,可以直接对目标系统复位。同时可以检测目标系统的复位情况,为了防止误触发应在目标端加上适当的上拉电阻。
  • Return Test Clock ( RTCK): 可选项,由目标端反馈给仿真器的时钟信号,用来同步 TCK 信号的产生,不使用时直接接地。

  JTAG 标准并没有定义 TAP 各引脚的布局方式,我们常见的调试器接口都有 20 个引脚(其源自于 ARM 给出的接口定义,详见后文),多出来的引脚都是一些电源、地等,布局基本就是如下图所示:
在这里插入图片描述

TAP Controller

  TAP controller 用于控制 JTAG 接口的行为。控制器主体是一个拥有 16 个状态的有限状态机(FSM,Finite State Machine),其状态跳变过程由 TMS 信号控制。TAP 控制器只能在 TCK 的上升沿改变状态,FSM 接下来跳转到哪个状态(next state),由 TMS 的电平以及 FSM 当前的状态(current state)决定。
在这里插入图片描述

SWD

  SWD(Serial Wire Debug)是由 ARM 公司设计的用于编程和调试 Cortex 系列微控制器的协议。由于 SWD 专门用于编程和调试,因此,它具有许多其他地方通常无法提供的特殊功能,例如通过 IO 线向计算机发送调试信息。

体系结构

  与将 TAP 链接在一起的 JTAG 相反,SWD 使用称为 DAP(Debug Access Port,调试访问端口)的总线。在这个 DAP 上,有一个主站(DP,Debug Port,调试端口)和一个或多个从站(AP,Access Port,接入端口),类似于 JTAG TAP。DP 使用包含 AP 地址的数据包与 AP 通信。
在这里插入图片描述

调试端口

调试端口是主机和 DAP 之间的接口。它还处理主机接口。有三种不同的调试端口可用于访问 DAP:

  • JTAG调试端口(JTAG-DP): 此端口使用标准的 JTAG 接口和协议来访问 DAP
  • 串行线调试端口 (SW-DP): 此端口使用 SWD 协议访问 DAP。
  • 串行线/JTAG调试端口(SWJ-DP): 此端口可以使用 JTAG 或 SWD 来访问 DAP。这是许多微控制器上的通用接口。它复用 JTAG 的 TMS 和 TCK 信号分别传输 SWDIO 和 SWDCLK 信号。必须发送特定的序列才能从一个接口切换到另一个接口。

访问端口

可以根据需要将多个 AP 添加到 DAP。ARM 提供了两个 AP 的规格:

  • 内存访问端口 (MEM-AP): 此 AP 提供对核心内存和寄存器的访问。
  • JTAG接入端口(JTAG-AP): 此 AP 允许将 JTAG 链连接到 DAP。

调试

  SWD 就只是用来调试(跟踪)的,因此它相对于 JTAG 简单不少,详细的调试协议在 《ARM® Debug Interface v5》的 The Serial Wire Debug Port (SW-DP) 这个章节有介绍。
在这里插入图片描述

固件烧录

  固件烧录的实现方式与 JTAG 中说的一样,就是协议走的 SWD 协议,这里就不再赘述了!

引脚

  SWD 协议定义了 2 个引脚,在体系结构方面支持星型拓扑。SWD 本身无固定电压,由目标板和目标芯片的 IO 供电电压决定,必须保证 JTAG 信号线与连接的芯片电压相同。

  • SWDIO: Serial Wire Data Input Output。主机发送的时钟信号。由于处理器时钟和 SWD 时钟之间没有关系,频率选择由主机接口决定。
  • SWCLK: Serial Wire Clock。这是带有来自 / 送到 DP 的数据的双向信号。数据由主机在上升边缘期间设置,并在 SWDCLK 信号的下降边缘期间由 DP 采样。

  SWD 实际上只是针对 ARM 处理器的 JTAG 的一个修改/实现,ARM 在其系统和接口设计参考文档中给出了常用的接口布局,成为了事实上的标准。通常它复用 JTAG 的 TMS 和 TCK 信号分别传输 SWDIO 和 SWDCLK 信号,从而允许用户使用 JTAG 或 SWD。
在这里插入图片描述
  除了调试信号,ARM 的 SWD 接口还指定了一个专用的引脚,允许目标 CPU 通过 UART 或 Manchester 协议在专用引脚上输出特定的数据,这个引脚被称为 SWO。并非所有支持 SWD 的 ARM 架构都支持 SWO。

调试

  根据 Queue.acm.org 的说法,“软件开发人员花费 35-50% 的时间验证和调试软件。调试、测试和验证的成本估计占软件开发项目总预算的 50% - 75%,每年超过100 亿美元。”

本地调试

  本地调试就是指调试使用的环境与调试的目标运行环境一致的调试方法(也有一种说法,只要调试环境和目标运行环境都在调试员眼前那就是本地调试)。在实际开发环境中,调试时不需要连接到远程调试端的调试方式就被称为本地调试。我们常用的 PC 程序开发的中的调试就是最常见的本地调试。
在这里插入图片描述

远程调试

  远程调试是调试环境与调试的目标运行环境不一致的情况下使用的调试方法(也有一种说法,如果要调试的目标运行环境不在调试员眼前的调试方法就是远程调试)。在实际开发环境中,调试时需要连接到远程调试端的调试方式就被称为远程调试。远程调试在嵌入式开发中最常用的调试方法。
在这里插入图片描述

调试器

  调试器是一个用来控制调试流程的软件程序,它执行调试命令,解析目标文件。我们常见的 IDE(Visual Studio、Android Studio、Keil、IAR)内部都包含了一个 GUI 调试器(不能拿出来单独使用),也有一些可独立使用的调试器,例如,WinDBG,OllyDBG、IDA 是独立的 GUI 调试器,DGB、LLDB 则是独立的命令行调试器。

  1. 命令行调试器通常也搭配第三方 GUI 工具来组建成 GUI 调试环境,例如,Eclipse、VSCode、DGBGUI 等
  2. 仿真器:现在,通常指嵌入式开发中的辅助调试设备(J-Link,ULINK、st-link 等),它支持调试、固件烧录等功能。
    在这里插入图片描述

  目前,大多数调试器都同时支持本地调试和远程调试,我主要从事嵌入式,因此,本文重点关注 gdb 调试器。gdb 调试器的远程调试最常用就是 gdbserver,他也是绝大部分远程调试的主要方式。

  gdb 调试器提供了两种不同的远程调试方法:stub(插桩)方式和 gdbserver 方式。其中,stub 方式则需要通过链接器把调试代理和要调试的程序链接成一个可执行的应用程序文件,而且 stub 需要修改异常处理和驱动程序等。gdbserver 是一个独立运行的单元,限制比较小。

嵌入式调试

  远程调试在嵌入式开发中最常用的调试方法(有人也将使用仿真器调试芯片称为本地调试,因为芯片开发板和调试 PC 都在眼前)。我认为,在调试时,不需要连接远程调试端的调试方式就是本地调试,需要连接到远程调试端的调试方式就是远程调试,与调试环境和运行环境无关! 所以,使用仿真器调试芯片如果直接调试芯片就是本地调试,如果通过启用远程调试端则就属于远程调试。我们常用的仿真器 J-Link、ST-LINK 等都同时提供本地调试和远程调试的能力。

如下是一些常用独立工具:

  • xPack Windows Build Tools:包括在 Windows 上执行构建所需的额外工具(make & rm)

  • xPack GNU Arm Embedded GCC:ARM 维护的官方 GNU ARM 嵌入工具链的一个代替,可以用于 Windows,MacOS和 GNU/Linux 平台。

  • xPack GNU RISC-V Embedded GCC:裸机 RISC-V GCC 发行版,由SiFive 维护。Windows、macOS 和 GNU/Linux 都有可用的二进制文件。

  • xPack OpenOCD:OpenOCD 的一个新发行版,为更好/更方便地与 OpenOCD 调试插件集成而定制。Windows、macOS 和GNU/Linux 都有可用的二进制文件。

  • xPack QEMU Arm:QEMU(开源机器仿真器)的一个分支,旨在为 Eclipse Embedded CDT 中 的Cortex-M 仿真提供支持。Windows、macOS 和 GNU/Linux都有可用的二进制文件。

  在线仿真(In-Circuit Emulation,ICE)原本是指的使用特殊硬件设备或在线模拟器来调试嵌入式系统的软件的方法。而如今,绝大多数芯片都支持 JTAG 调试接口,这种情况下可以在直接在目标芯片上调试,没有仿真,但是人们仍然使用仿真这个概念。

片上调试(On-Chip Debugging)是在线仿真的一种方法,目前最常用的实现方案就是 JTAG。

J-Link

  J-Link 的驱动程序包里包含很多实用工具,我们直接使用 J-Link 调试芯片时默认就是本地调试,但是,J-Link 提供了一个名为 J-Link GDB Server 的程序来提供远程调试功能。
在这里插入图片描述

ST-LINK

  ST 官方提供了 ST-LINK server 或 The STM32CubeIDE ST-LINK GDB server 来提供对于 ST-LINK 的远程调试功能,此外,开源的 stlink 库也提供了一些使用工具,其中也包含提供远程调试的工具。

OpenOCD

  OpenOCD(Open On-Chip Debugger)是一个开源的片上调试器,旨在提供针对嵌入式设备的调试、系统编程和边界扫描功能。直观点说,OpenOCD 就是一个连通 gdb 和硬件仿真器的(命令行)软件程序。
在这里插入图片描述
  OpenOCD 支持大量的仿真器,包括但不限于各种加密狗、USB FT2232(FTDI) 系列、USB-JTAG / Altera USB-Blaster、J-Link、RLINK、ST-LINK 等等,官方文档 https://openocd.org/doc/html/Debug-Adapter-Hardware.html 有详细列表。

基本使用流程:

  1. openocd -f xxx.cfg 如果有多个配置文件则可以多次使用 -f xxx.cfg 来指定多个配置文件。OpenOCD 会自动启动 gdbserver
  2. gdb xxx 进入调试我们的程序模式
  3. target remote localhost:3333 连接到远程 gdbserver

断点

  断点是调试器 / 仿真器设置源程序在执行过程中自动进入中断模式的一个标记。当程序运行到断点时,程序中断执行(程序中断后,断点所在的行还没有执行)。通过设置断点可以查找程序运行时的错误,是调试程序常用的手段。

硬件断点

  硬件断点是由芯片内部的逻辑电路实现的,实际上就是芯片内的比较器,将当前 PC 值与比较器中的地址进行比较,当检测到指令地址总线上断点的地址值时,就会暂停 CPU 将控制权转移到调试器。

  硬件断点比软件断点更强大、更灵活,能够设置在代码的任何位置(FLASH、RAM),但是,CPU 只有有限数量的硬件断点(比较器)。ARM 7/9 内核有 2 个,Cortex-M内核则有 4 ~ 8 个,x86 则通常为 4 个。

J-Link 支持一项名为 无限 Flash 断点(Unlimited Flash Breakpoints) 的调试功能,该功能允许用户在 Flash 中调试时设置无限数量的断点。

软件断点

  软件断点实际上是通过用断点指令替换要被断点的指令来设置的。断点指令存在于大多数 CPU 中,通常和最短的指令一样短,所以 x86 上只有一个字节(0xcc,INT 3)。在 Cortex-M CPU 上,指令是 2 或 4 字节,所以断点指令是一个 2 字节的指令。

  由于软件断点需要执行替换操作,所以软件断点只能设置在 RAM 里面,好处是基本不受数量的限制(理论不受限制,实际取决于使用的仿真器)!此外,软件断点还可以在替换指令时添加指定判断条件,因此,可分为无条件断点和有条件断点。如下是 Keil 中的 Access breakpoint 的设置界面:
在这里插入图片描述

参考

  1. https://learn.sparkfun.com/tutorials/arm-programming/jtag-and-swd
  2. https://embeddedinventor.com/swd-vs-jtag-differences-explained/
  3. https://www.corelis.com/education/tutorials/jtag-tutorial/what-is-jtag/
  4. https://www.xjtag.com/about-jtag/what-is-jtag/
  5. https://research.kudelskisecurity.com/2019/05/16/swd-arms-alternative-to-jtag/
  6. https://vlsitutorials.com/jtag-test-access-port-and-tap-controller/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/359530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文本生成图像应用指南【Stable Diffusion】

Stable Diffusion 是一种文本到图像的潜在扩散模型,由来自 CompVis、Stability AI 和 LAION 的研究人员和工程师创建。 它使用来自 LAION-5B 数据库子集的 512x512 图像进行训练。 稳定扩散,生成人脸,也可以在自己的机器上运行,如…

车载技术开发—{Android CarFrameWork}

Android Automotive平台 Android Automotive是通过Android的通用框架,语言和API来实现的一个全栈,开源,高度可定制的平台。 Android Automotive与整个Android生态系统的关系 Android Automotive是Android的一部分。 Android Automotive不是…

pbootcms被黑木马问题(3)

昨天经过同事告知发现了很早之间做的几个企业官方都中木马了,然后看了一下木马情况,跟之间的两次都有所不同,这里记录一下新的木马的清理过程,有遇到的朋友可以借鉴一下。(之前有做过一些防止批量扫站的措施,因为嫌麻烦就没有给这些网站上进行修改&#…

【Spark分布式内存计算框架——Spark SQL】13. 自定义UDF函数

第七章 自定义UDF函数 无论Hive还是SparkSQL分析处理数据时,往往需要使用函数,SparkSQL模块本身自带很多实现公共功能的函数,在org.apache.spark.sql.functions中。SparkSQL与Hive一样支持定义函数:UDF和UDAF,尤其是U…

黑格尔的实践观探究

(江苏大学马克思主义学院 212000)一、引言人的独特性在于实践活动,以及由实践活动带来的人类社会的不断进化与发展。人类的实践史体现了人的全部本质。但是,人类从理论的高度反思自己的实践活动,尤其是在哲学的层面上进…

【基础算法】之 冒泡排序优化

冒泡排序思想基本思想: 冒泡排序,类似于水中冒泡,较大的数沉下去,较小的数慢慢冒起来(假设从小到大),即为较大的数慢慢往后排,较小的数慢慢往前排。直观表达,每一趟遍历,…

大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——shuffle机制

3.3.1Shuffle机制 Map方法之后,Reduce方法之前的数据处理过程称之为Shuffle。 3.3.2Partition分区 1、问题引出 要求将统计结果按照条件输出到不同文件中(分区)。比如:将统计结果按照手机归属地不同省份输出到不同文件中&#…

2023春季露营投影怎么选?轻薄投影极米Z6X Pro值得推荐

近年来,露营经济在多重因素的共同助推下快速发展,精致露营的攻略开始占据小红书、微博、朋友圈等各类社交平台,吸引着更多用户种草并加入到露营大军中,而露营经济的强势“破圈”给家用智能投影带来了更多的发展契机。凭借着小巧的…

探访上汽通用武汉奥特能超级工厂

上汽通用汽车在电动化和智能网联化新技术领域投入了700亿大洋,武汉奥特能超级工厂就是其中一个重点项目。这个工厂已经投产,将成为上汽通用汽车的新能源生产基地,加速奥特能平台车型的推出。 最近别克推出了Electra E5,它是别克第…

新品BCM6755A1KFEBG/MT7921LE/MT7921AU WiFi芯片

博通在WiFi市场具有相当的实力。在WiFi6上有下面这几个解决方案:型号:BCM6755 BCM6755A1KFEBG类型:四核1.5GHz CPU封装:BGA批次:新BCM6755和BCM6750还是A7架构,更多的用在中低端型号上。BCM6755和BCM6750 C…

Spark 广播变量累加器

广播变量 场景描述:一份数据存在Driver中,但是每个Executor都需要一份。 常规模式下,Driver会给每个分区都发送一份数据。如果在Executor中存在多个分区的情况,那么一个Executor会获得多份数据。 Executor是进程,task…

微信小程序阻止页面返回(包滑动、自动返回键)

这个场景还是挺有意思的,比如某多多,只要你点左上角的返回 好家伙,满满又 花不了 的优惠券就来了,让你拥有一种消费最划算的感觉。 如果你的场景比较简单,只是对左上角的返回进行监听,只需要关闭自带的导航…

16_FreeRTOS队列集

目录 队列集 队列集相关API函数介绍 队列集使用流程 实验源码 队列集 一个队列只允许任务间传递的消息为同一种数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集! 作用:用于对多个队列或信号量进行“监听”其中不管哪一个消息到来,都…

JVM学习笔记四:运行时数据区之虚拟机栈

目录 概述 StackOverflowError测试案例 栈运行原理 栈帧的内部结构 改变栈帧大小的StackOverflowError测试案例 局部变量表 局部变量槽 操作数栈 动态链接 静态链接 动态链接 早期绑定 晚期绑定 方法返回地址 概述 与程序计数器一样,Java虚拟机栈也是…

4665: 求前n项和

描述给定序列&#xff1a;求前n项之和。输入输入数据有多组&#xff0c;第一行为数据的组数t&#xff08;1<t<15&#xff09;。每组数据有一行&#xff0c;每行为一个正整数n&#xff08;n<1000000&#xff09;。输出每组输出前n项的和&#xff0c;保留4位小数。样例输…

【编程入门】应用市场(安卓版)

背景 前面已输出多个系列&#xff1a; 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 《N种编程语言做个记事本》 目标 为编程初学者打造入门学习项目&#xff0c;使…

Jmeter常用断言之BeanShell断言详解

BeanShell断言可以使用beanshell脚本来执行断言检查&#xff0c;可以用于更复杂的个性化需求&#xff0c;使用更灵活&#xff0c;功能更强大&#xff0c;但是要能够熟练使用beanshell脚本 在这里除了可以使用beanshell的内置变量外&#xff0c;主要通过 Failure 和 FailureMess…

es 7.8.0 linux 集群

1. 下载es linux版本的数据包 地址: https://www.elastic.co/cn/downloads/past-releases#elasticsearch 解压: 解压 tar -xzvf xxx 2. 我是在一个服务器上测试的,实际上是不同的服务器 所以复制了三份,模拟多节点 进去之后主要是修改elasticsearch.yml 内容如下 节点一…

关于在VM上的windows server 2022系统安装

目录 1、windows serer 2022安装的准备工作 1&#xff09;下载系统 2&#xff09;寻找对应系统密钥 3&#xff09;配置server系统开机配置项&#xff08;可能会出现sconfig配置界面&#xff09; 2、开始安装server系统 1、windows serer 2022安装的准备工作 1&#xff09;…

Dropout

目录一、Dropout出现的原因二、什么是Dropout&#xff1f;三、为什么Dropout解决过拟合?3.1 取平均的作用3.2 减少神经元间复杂的共适应关系四、实现Dropout—— pytorchexample 1example 2example 3设置dropout参数技巧一、Dropout出现的原因 在机器学习的模型中 如果模型的…