RISC-V debug专栏2 --- Debug Module(DM)
Debug Module(DM)的核心功能
DM 就像一个翻译官,负责把调试器的抽象指令(比如 “暂停处理器”)转换成硬件能听懂的具体操作。它必须实现以下基本功能:
- 必要功能(必须实现):
- 暂停 / 恢复任意处理器核心(hart)。
- 告诉调试器哪些核心已经暂停。
- 读写暂停状态下的核心寄存器(比如通用寄存器 GPR)。
- 提供复位信号,确保能从启动第一条指令开始调试。
- 可选功能(根据设计选择):
- 直接读写非通用寄存器(如 CSR)。
- 用 “程序缓冲区” 让核心执行任意指令(比如访问内存)。
- 同时控制多个核心暂停 / 恢复。
- 直接访问系统总线(无需通过核心)。
1. DM 的接口(DMI 总线)
DM 通过DMI 总线与调试主机通信,就像电脑通过 USB 连接外设一样:
- 主设备是调试主机(如运行 GDB 的电脑)。
- 从设备是 DM 和其他调试模块(如多个 DM 或自定义设备)。
- 地址空间:DM 的地址从最低位开始,额外地址可分配给其他设备。例如:
2. Reset control
DM 负责管理系统的全局复位信号(ndmreset / non debug module reset):
- 作用:除 DM 和Debug Transport模块之外的所有组件会被复位或保持在复位状态。具体哪些部件被复位由芯片厂商决定,但必须保证调试器能从程序第一条指令开始调试。
- 规则:
- DM模块自己的状态和寄存器只有两种情况会被复位:
a. 系统刚上电时
b. 当 dmcontrol 寄存器中的 dmactive 位为 0 时(即调试功能未激活) - 如果调试功能激活(dmactive=1),系统复位时 HART 的暂停状态会被保留(比如断点位置),但触发相关的 CSR 寄存器可能会被清除
- 由于时钟和电源域的设计问题,系统复位时不能随意进行 DMI 访问
- 此时唯一允许的操作是读写 dmcontrol 寄存器,其他 DMI 操作会导致不可预测的结果
- DM模块自己的状态和寄存器只有两种情况会被复位:
-
ndmreset 的操作规则
- 复位信号的持续时间没有强制要求,但必须满足:
a. 先写 1 使能复位
b. 再写 0 触发实际复位 - 系统恢复时间不确定,通过 allunavail/anyunavail 寄存器报告
- 复位信号的持续时间没有强制要求,但必须满足:
-
单个 HART 的复位方法
- 通过选择目标 HART,设置并清除 hartreset 位实现复位
- 实际复位可能包括未被选中的 HART(厂商实现差异)
-
复位状态检测
- 调试器可通过以下方式确认复位情况:
a. anyhavereset:是否有至少一个选中 HART 处于复位状态
b. allhavereset:是否所有选中 HART 都处于复位状态
- 调试器可通过以下方式确认复位情况:
-
复位标志的清除规则
- 复位后 HART 会设置粘性标志(必须手动清除)
- 清除方法:向 dmcontrol 的 ackhavereset 位写 1
- 特殊情况:当 dmactive=0 时,标志可能自动清除
-
复位后的 HART 行为
- 如果设置了 haltreq 或 resethaltreq:
- 复位后立即进入调试模式
- 否则:
- 正常执行程序
- 如果设置了 haltreq 或 resethaltreq:
3. selecting Harts
- 一个调试模块(DM)最多可以连接 2^20 个硬件线程(hart)。调试器需要先选择一个特定的 hart,之后对这个 hart 发出的暂停、恢复、复位和调试等命令就都只针对这个被选中的 hart 起作用。
- 调试器如果要列出所有的 hart,需要先确定
HARTSELLEN
的值。
- 把
hartsel
寄存器里的所有位都设为 1(假定hartsel
有最大的位宽),接着读取hartsel
的值,这样就能知道哪些位实际上被设置了,从而确定HARTSELLEN
(即hartsel
寄存器里有效位的数量)。 - 从索引为 0 的 hart 开始,逐个选择 hart,直到
dmstatus
寄存器里的anynonexistent
位变为 1(这表明后面没有可用的 hart 了),或者达到了HARTSELLEN
所限制的最大索引。
- 调试器可以通过接口读取
mhartid
寄存器,或者读取系统的配置字符串,来了解 hart 索引和mhartid
之间的映射关系。
3.1 选择单个hart
- 所有的调试模块都必须支持选择单个 hart。调试器选择单个 hart 的方法很简单,就是把要选的 hart 的索引值写到
hartsel
寄存器里。hart 的索引是从 0 开始的,而且是连续编号的,一直到最后一个索引。
举个例子,要是你想选择第 3 个 hart(索引为 2,因为索引从 0 开始),就把数值 2 写入 hartsel
寄存器。之后执行的暂停、恢复、复位和调试命令都只会对这个被选中的 hart 起作用。
3.2 选择多个hart
- 调试模块可以实现一个 Hart 数组掩码寄存器,这样就能一次选择多个 hart 了。这个 Hart 数组掩码寄存器的第 n 位对应索引为 n 的 hart,如果这一位是 1,就表示选中了这个 hart。通常,一个 DM 的 Hart 数组掩码寄存器的位宽刚好能覆盖它所支持的所有 hart,但也允许把其中某些位固定设为 0。
- 调试器可以通过
hawindowsel
和hawindow
来设置 Hart 数组掩码寄存器里的位,然后设置hasel
来对所有被选中的 hart 执行操作。如果支持这个功能,就可以同时对多个 hart 进行暂停、恢复和复位操作。而且,设置或清除hasel
不会影响 Hart 数组掩码寄存器的状态。 - 只有通过
dmcontrol
发起的操作才能同时作用于多个 hart,而抽象命令(Abstract Commands)只对通过hartsel
选中的单个 hart 起作用。
4. Hart States
每个可被选中的 Hart(硬件线程)必定处于以下四种状态之一:
- 不存在(Nonexistent)
- 不可用(Unavailable)
- 运行中(Running)
- 暂停(Halted)
状态详解
a. 不存在(Nonexistent)
- 含义:这个 Hart 在系统中根本不存在,无论等多久都不会出现。
- 例子:
假设系统只有 1 个 Hart(索引 0),那么索引 1 及以上的 Hart 都是 “不存在” 的。 - 调试器行为:
调试器遇到第一个不存在的 Hart 后,会认为后面所有索引的 Hart 都不存在。
b. 不可用(Unavailable)
- 含义:Hart 可能暂时无法使用,或者被系统永久禁用(比如工厂关闭)。
- 可能原因:
- 正在复位(Reset)
- 暂时断电
- 未插入系统(如扩展卡未安装)
- 制造时被永久禁用(导致 Hart 索引不连续)
- 调试器行为:
即使 Hart 永远不会可用,调试器也必须将其视为 “不可用”,以便正确枚举所有可能的 Hart。
c. 运行中(Running)
- 含义:Hart 正在正常执行程序,就像没有调试器连接一样。
- 特点:
- 可能处于低功耗模式或等待中断,但调试器可以通过暂停请求(
haltreq
)让它进入暂停状态。 - 例如:手机 CPU 在省电模式下运行,但仍能被调试器暂停。
- 可能处于低功耗模式或等待中断,但调试器可以通过暂停请求(
d. 暂停(Halted)
- 含义:Hart 被调试器暂停,只能执行调试器的命令(如单步执行、读写寄存器)。
- 特点:
- 处于调试模式,无法自主运行程序。
- 例如:调试器设置断点后,Hart 会暂停在此处等待调试指令。
复位后的状态变化
- 复位期间:Hart 可能处于 “不可用” 状态。
- 复位结束后:
- Hart 可能短暂进入 “运行中” 状态(比如执行初始化代码)。
- 最终根据调试器的配置(
haltreq
和resethaltreq
)决定是继续运行还是暂停。
状态判断工具
调试器通过dmstatus
寄存器的以下标志位判断状态:
allnonexistent
:所有 Hart 都不存在(罕见)。anynonexistent
:存在至少一个不存在的 Hart。allunavail
:所有 Hart 都不可用。anyunavail
:存在至少一个不可用的 Hart。allrunning
:所有 Hart 都在运行。anyrunning
:存在至少一个运行中的 Hart。allhalted
:所有 Hart 都被暂停。anyhalted
:存在至少一个被暂停的 Hart。
总结
- 不存在:系统中没有这个 Hart。
- 不可用:Hart 可能存在,但暂时或永久无法使用。
- 运行中:Hart 正常执行程序,可被调试器暂停。
- 暂停:Hart 被调试器控制,只能执行调试命令。
通过这些状态,调试器可以精准控制和监控每个 Hart 的行为。
5. Run Control
基本概念
调试模块(DM)会为每个 hart 记录 4 个概念上的状态位:
- 暂停请求(halt request):就像老师让学生停下来别写作业了。
- 恢复确认(resume ack):好比学生收到老师让继续写作业的通知后,给老师一个确认的回复。
- 复位时暂停请求(halt - on - reset request):可以想象成在重新开始考试前,老师要求学生先别动笔。
- 硬件线程复位(hart reset):类似于把电脑重启一下。
除了恢复确认位可能初始化为 0 或者 1,其他 3 个位初始都为 0。
状态信号
DM 会从每个 hart 接收 “已暂停(halted)”“正在运行(running)” 和 “已复位(havereset)” 这些信号。调试器能通过一些寄存器看到恢复确认位的状态,以及 “已暂停”“正在运行”“已复位” 信号的状态,但其他位的状态不能直接看到。
暂停请求操作
当调试器把 haltreq
设为 1 时,就好像老师喊了一声 “都别写了”,每个被选中的 hart 的暂停请求位就会被设置。如果一个 hart 正在运行,或者刚从复位状态恢复,看到自己的暂停请求位被设置了,它就会停下来,就像学生听到老师的话停下手中的笔。同时,它会取消 “正在运行” 信号,发出 “已暂停” 信号。要是 hart 本来就已经暂停了,就会忽略这个暂停请求位,就像已经停下笔的学生不会再因为老师重复 “别写了” 而有额外反应。
恢复请求操作
当调试器把 resumereq
设为 1 时,好比老师说 “可以继续写作业了”。这时,每个被选中的 hart 的恢复确认位会被清除,并且每个被选中且处于暂停状态的 hart 会收到恢复请求。hart 收到请求后,就会继续工作,就像学生继续写作业,同时取消 “已暂停” 信号,发出 “正在运行” 信号。最后,恢复确认位会被设置,表示已经确认恢复。正在运行的 hart 会忽略恢复请求,就像一直在写作业的学生不会因为老师重复 “继续写” 而有额外反应。
响应时间要求
当请求暂停或者恢复时,除非 hart 不可用,否则它必须在 1 秒内做出响应。不过一般来说,可能几个时钟周期就会有反应,就像学生听到老师的话马上就会做出动作。
复位时暂停请求操作
DM 可以为每个 hart 实现可选的 “复位时暂停请求” 位。当 DM 把 hasresethaltreq
设为 1 时,就表示它支持这个功能。调试器把 setresethaltreq
设为 1,就像老师在重新开始考试前说 “大家先别动笔”,每个被选中的 hart 的 “复位时暂停请求” 位就会被设置。当这个位被设置后,下次 hart 复位结束,它会马上进入调试模式,不管复位是什么原因引起的。这个位会一直保持设置状态,直到调试器把 clrresethaltreq
设为 1 来清除它,或者 DM 进行复位,就像老师说 “可以开始考试了”,学生才会开始动笔。
总结
调试模块通过设置不同的控制位,就像老师给学生发指令一样,来控制 hart 的运行、暂停和复位等状态,并且能根据 hart 反馈的信号了解它的状态。同时,对 hart 的响应时间也有一定要求。
6. Abstract Command
抽象命令概述
调试模块(DM)支持一组抽象命令,不过大部分命令是可选的。这就好比一个工具包,里面有很多工具,但不是每个工具都一定会被用到。
有时候,就算被选中的硬件线程(hart)没有暂停,调试器也能执行某些抽象命令。就好像你在一台电脑运行程序的时候,也能对它进行一些简单的设置操作。
调试器要知道某个 hart 在特定状态下支持哪些抽象命令,只能通过实际去尝试执行这些命令,然后查看 abstractcs
寄存器里的 cmderr
值,看看命令是否执行成功。就像你想知道一个新玩具能做哪些动作,只能亲自去操作一下,看看它能不能按你的要求做出反应。
而且有些命令在设置了某些选项时能支持,设置其他选项时就不支持了。如果设置了不支持的选项,DM 会把 cmderr
设置为 2,表示 “不支持”。比如一个游戏,有些难度级别是支持的,有些难度级别是不支持的,你选了不支持的难度,游戏就会提示你不行。
执行抽象命令的过程
调试器执行抽象命令时,就像给 DM 下指令,要把命令写到 command
寄存器里。然后,通过读取 abstractcs
寄存器里的 busy
位,就能知道命令是否执行完了。命令执行完后,cmderr
会告诉你命令是否成功。命令可能会失败,原因可能是 hart 没暂停、没运行、不可用,或者执行过程中遇到了错误。这就好比你让一个工人完成一项任务,你可以通过看他是不是还在忙(busy
)来知道任务有没有完成,最后通过任务的结果(cmderr
)来判断是否成功。
如果命令需要参数,调试器得在写命令到 command
寄存器之前,先把参数写到数据寄存器里。要是命令有返回结果,DM 得在 busy
位清零之前,把结果放到数据寄存器里。具体用哪些数据寄存器存参数在表格 3.1 里有说明,而且最低有效字要放在编号最小的数据寄存器里。参数的宽度取决于执行的命令,没明确指定时就是 DXLEN
。这就好比你给工人布置任务时,要先把任务所需的材料(参数)准备好放在指定的地方,等任务完成后,工人要把结果也放在指定的地方。
抽象命令接口的设计目的
抽象命令接口的设计是为了让调试器能尽快地发出命令,之后再去检查命令是否无错完成。一般情况下,调试器的速度比目标硬件慢很多,而且命令通常能成功执行,这样就能实现最大的吞吐量。要是有命令失败了,这个接口能保证失败的命令之后不会再执行其他命令。调试器要找出是哪个命令失败了,就得查看 DM 的状态(比如 data0
寄存器的内容)或者 hart 的状态(比如被程序缓冲区程序修改的寄存器内容)。这就好比你给一群工人依次布置任务,先快速把任务都布置下去,之后再检查任务完成情况。如果有一个任务失败了,后面的任务就先不执行了,然后通过查看相关的工作记录(DM 或 hart 的状态)来找出是哪个任务出了问题。
执行抽象命令的限制条件
在开始执行抽象命令之前,调试器得确保 haltreq
、resumereq
和 ackhavereset
这几个位都是 0。这就好比你要让工人开始一项新任务,得先确保之前的暂停、恢复和复位相关的事情都处理好了。
当抽象命令在执行时(abstractcs
里的 busy
位为高),调试器不能改变 hartsel
(选择的 hart),也不能把 haltreq
、resumereq
、ackhavereset
、setresethaltreq
或 clrresethaltreq
这些位设置为 1。这就好比工人在干活的时候,你不能随便换工人,也不能突然让他暂停、恢复或者复位。
处理命令执行异常的情况
如果一个抽象命令没在预期时间内完成,看起来像是卡住了,调试器可以尝试下面的步骤来中止这个命令:先复位 hart(用 hartreset
或 ndmreset
),然后复位 DM(用 dmactive
)。这就好比工人干活卡住了,你先把他 “重启” 一下,再把工作环境 “重启” 一下。
如果在所选的 hart 不可用的时候启动抽象命令,或者在执行抽象命令时 hart 变得不可用了,DM 可能会终止这个抽象命令,把 busy
位清零,把 cmderr
设置为 4(表示 “暂停 / 恢复” 问题)。也有可能命令看起来就像卡住了(busy
位一直不清零)。这就好比工人突然生病了(hart 不可用),正在做的任务可能就做不下去了,要么直接停止,要么就一直卡在那里。
6.1 Abstract command list
- 0x0000 - 0x0fff:放的是 CSRs(控制状态寄存器),这里面可以通过
dpc
这个 “快捷方式” 访问 “PC”(程序计数器,类似记录你正在看哪一页书的标记)。 - 0x1000 - 0x101f:放的是 GPRs(通用寄存器,像通用抽屉,啥都能临时放一点)。
- 0x1020 - 0x103f:放的是浮点寄存器(专门放小数相关数据的抽屉)。
- 0xc000 - 0xffff:留着以后给特殊扩展功能或内部用的,现在先空着。
- cmdtype:等于 0 时,代表这个命令是 “Access Register”(访问寄存器),就像给调试器一个 “访问寄存器” 的任务标签。
- aarsize:决定访问寄存器时拿多少数据。2 是拿 32 位(一小份),3 是拿 64 位(中等份),4 是拿 128 位(一大份)。如果要拿的量比寄存器实际能给的多,访问就会失败。
- aarpostincrement:如果是 1,比如你访问了 0 号寄存器,访问完后,下次自动变成访问 1 号寄存器(像自动翻页)。0 就是没这功能。
- postexec:如果是 1,在完成数据转移(读或写寄存器)后,去执行 “程序缓冲区” 里的程序(像做完一件事,再顺手做另一件事)。0 就是不做。
- transfer:配合
write
用。1 表示要按write
的指示做操作(读或写寄存器)。 - write:当
transfer
是 1 时,0 表示从寄存器读数据到arg0
(从抽屉拿东西放篮子);1 表示从arg0
写数据到寄存器(把篮子东西放抽屉)。 - regno:要访问的寄存器编号,像抽屉号码。
“Access Register” 命令就像调试器当 “寄存器管理员”,对 CPU 寄存器进行操作,还能执行一个小任务(程序缓冲区)。举例:
- 读寄存器:比如你想看看 3 号寄存器(
regno = 3
)里的内容。设置write = 0
(不写),transfer = 1
(要操作)。调试器就像从 3 号抽屉里把东西拿出来,放到arg0
这个篮子里。 - 写寄存器:如果想把
arg0
篮子里的东西放到 5 号寄存器(regno = 5
)。设置write = 1
(写),transfer = 1
(要操作)。调试器就把篮子东西放进 5 号抽屉。 - 自动递增编号:如果
aarpostincrement = 1
,假设先访问 2 号寄存器,访问完后,下次regno
自动变成 3 号(像自动从第 2 页翻到第 3 页)。 - 执行程序缓冲区:如果
postexec = 1
,在完成读或写寄存器后,调试器会去执行 “程序缓冲区” 里的程序(像做完作业,再去做手工)。
- 调试模块必须实现这个命令。而且当硬件线程(hart)“暂停”(像上课喊停,学生不动)时,必须支持读写所有 GPRs(通用寄存器,那些通用抽屉)。
- 对于其他寄存器(比如浮点寄存器),支持情况不一定。可能有的寄存器只能读不能写,或者在 hart 运行时(像学生正常上课)也能访问,也可能不行。每个寄存器在 “读、写、hart 状态(暂停或运行)” 下的支持情况都可能不同。
- 如果操作中任何一步失败(比如要访问的寄存器根本不存在),
cmderr
会被设置(像报错),后面步骤也不做了。比如要开一个不存在的抽屉,直接报错,不再继续开其他抽屉。
通过这些操作,调试器就能灵活地和 CPU 寄存器 “打交道”,就像管理员管理抽屉一样,按需读写,还能在适当时候执行小任务。
6.2 快速访问
当 cmdtype
为 1 时,表示这是一个 “Quick Access command(快速访问命令)
命令操作通俗解释
- 检查 hart 是否已暂停:
假如把 hart 想象成一个正在工作的小机器人。如果这个小机器人已经停下来(暂停)了,就像机器人正在休息,这时这个命令会给cmderr
设置为 “halt/resume”(暂停 / 恢复相关的错误标记),然后不再继续下面的操作。就好比你看到一个人已经坐下休息了,还非要让他坐下,那就会报错说 “别重复啦”。 - 尝试让 hart 暂停:
现在要让这个小机器人停下来。但如果小机器人因为其他原因(比如遇到了一个 “小陷阱”—— 断点)自己停下来了,那这个命令也会给cmderr
设置为 “halt/resume”,不再继续下面的操作。这就像你让朋友帮忙去买东西,结果朋友因为路上看到喜欢的店自己先停下了,那你的任务就没法按计划进行,得报错。 - 执行程序缓冲区:
让小机器人去执行一个 “小任务包”(程序缓冲区)。如果在执行这个 “小任务包” 时出了问题(异常),就像小机器人在执行任务时摔了一跤,这时会给cmderr
设置为 “exception”(异常标记),“小任务包” 的执行结束,但这个快速访问命令还会继续往下走。就好比你让朋友去取快递,朋友取快递时遇到点问题,但你还是让朋友继续后面的行程。 - 恢复 hart 运行:
最后让小机器人重新开始工作(恢复运行)。
总结
这个 “Quick Access command” 是一个可选的命令(不是必须有的功能),而且在整个过程中,它不会去动数据寄存器(就像一个人只负责发号施令让机器人动,但不碰机器人携带的包裹 —— 数据寄存器)。通过这几个步骤,调试器可以在一定条件下控制 hart 的暂停、执行特定任务包,然后再恢复运行,但每一步都有相应的规则和错误处理机制。
6.3 内存访问
cmdtype
:值为 2,代表这是 “访问内存命令(Access Memory Command)”
aamvirtual
:- 0:表示访问的是物理地址(就像直接按实际房间号找房间),操作直接在硬件线程(hart)对应的物理内存上进行。
- 1:表示访问的是虚拟地址,且会像在机器模式(M - mode)下设置了
MPRV
那样进行地址转换(类似通过门牌号对应的虚拟映射找房间)。
aamsize
:决定访问内存区域的大小。- 0:访问内存位置的最低 8 位(1 字节,像从一个大箱子里拿 1 小格东西)。
- 1:访问最低 16 位(2 字节,拿 2 小格)。
- 2:访问最低 32 位(4 字节,拿 4 小格)。
- 3:访问最低 64 位(8 字节,拿 8 小格)。
- 4:访问最低 128 位(16 字节,拿 16 小格)。
aampostincrement
:- 1:内存访问完成后,
arg1
(存地址的地方)会按aamsize
编码的字节数增加(比如aamsize
是 2,访问 4 字节,arg1
地址就 +4,像自动翻到下一页地址)。 - 0:无此效果。
- 1:内存访问完成后,
write
:- 0:从
arg1
指定的内存位置读数据到arg0
(像从书架上拿书到自己手里)。 - 1:把
arg0
的数据写到arg1
指定的内存位置(像把手里的书放回书架)。
- 0:从
target - specific
:留给特定目标用的保留位(暂时不用管,像预留的特殊通道)。
命令操作通俗解释(结合例子)
“访问内存命令(Access Memory)” 让调试器能像被选中的硬件线程(hart)一样访问内存,包括 hart 本地的内存映射寄存器等(好比调试器 “模仿” hart 去开它能开的抽屉)。
- 读操作示例:
假设aamsize = 2
(访问 32 位,4 字节),write = 0
(读),arg1
里存的地址是0x1000
。调试器就从内存地址0x1000
处读 4 字节数据到arg0
(像从0x1000
这个抽屉里拿 4 件东西放到篮子arg0
里)。如果aampostincrement = 1
,读完后arg1
会变成0x1004
(地址自动加 4,准备好下次读下一个抽屉)。 - 写操作示例:
若write = 1
(写),arg0
里有数据,arg1
地址是0x2000
,aamsize = 3
(访问 64 位,8 字节)。调试器会把arg0
的数据写到内存地址0x2000
处(像把篮子arg0
里的东西放到0x2000
这个抽屉里)。 - 失败处理:
如果这些操作中任何一步失败(比如 hart 在机器模式下执行相同访问也会失败的情况),就设置cmderr
(报错),后面步骤不再执行(像发现抽屉坏了,马上停止操作并标记问题)。
命令支持情况
调试模块可以选择实现这个命令,并且可以支持在 hart 运行或暂停时访问内存位置。如果支持 hart 运行时的内存访问,那也必须支持 hart 暂停时的内存访问(好比如果允许在白天用某工具,那晚上也得允许用)。这个命令只有在读内存时会修改 arg0
,只有设置了 aampostincrement
才会修改 arg1
,其他数据寄存器不受影响(像只动特定的篮子和抽屉编号,其他篮子不动)。
相关文章:
RISC-V debug专栏2 --- Debug Module(DM)
Debug Module(DM)的核心功能 DM 就像一个翻译官,负责把调试器的抽象指令(比如 “暂停处理器”)转换成硬件能听懂的具体操作。它必须实现以下基本功能: 必要功能(必须实现)ÿ…...
LLM 分词器Tokenizer 如何从 0 到 1 训练出来
写在前面 大型语言模型(LLM)处理的是人类的自然语言,但计算机本质上只能理解数字。Tokenizer(分词器) 就是架在自然语言和计算机数字表示之间的一座至关重要的桥梁。它负责将我们输入的文本字符串分解成模型能够理解的最小单元——Token,并将这些 Token 转换成对应的数字…...
蓝桥杯冲刺:一维前缀和
系列文章目录 蓝桥杯系列:一维前缀和 文章目录 系列文章目录前言一、暴力的写法:二、一维前缀和的模板: 具体实现: 三、具体例题:求和 1.题目参考:2.以下是具体代码实现: 总结 前言 上次我介绍…...
光学关键尺寸量测设备市场报告:2024年全球市场销售额达到了14.75亿美元
一、引言 光学关键尺寸量测设备作为半导体制造、精密加工等领域的核心工具,其重要性不言而喻。随着科技的飞速发展,这些设备在提升产品精度、缩短研发周期、降低生产成本等方面发挥着越来越关键的作用。本报告旨在深入分析光学关键尺寸量测设备的技术特…...
链表的操作-反转链表
链表 160相交链表 代码 class Solution { public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode* h1headA;ListNode* h2headB;while(h1&&h2){if(h1!h2){h1h1->next;h2h2->next;}else{return h1;}}if(h1nullptr){h1headB;}else{h…...
2025 年浙江危化品经营单位考试攻略分享
浙江的考试由省应急管理部门主导。理论考试突出危化品在电商、物流等新兴业态下的安全管理知识,这与浙江发达的电商产业紧密相关。对危险化学品的环境危害及防治知识考查细致。实际操作考核模拟杭州、宁波等地危化品仓储物流中心的作业情况。 报名材料准备齐全后…...
python使用cookie、session、selenium实现网站登录(爬取信息)
一、使用cookie 这段代码演示了如何使用Python的urllib和http.cookiejar模块来实现网站的模拟登录,并在登录后访问需要认证的页面。 # 导入必要的库 import requests from urllib import request, parse# 1. 导入http.cookiejar模块中的CookieJar类,用…...
STM32开发板上生成PWM正弦波
在STM32开发板上生成正弦波通常需要结合定时器(TIM)、数模转换器(DAC)或脉宽调制(PWM)以及时钟系统的配置。以下是分步指南: 方法1:使用DAC 定时器(推荐) 步…...
Spring Boot 实现文件秒传功能
前言 在开发Web应用时,文件上传是一个常见需求。然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余。此时可以使用文件秒传技术通过识别重复文件,实现瞬间完成上传的效果,大大提升了用户体验…...
【Vue2】数据绑定_MVVM模型_数据代理_事件处理
目录 一、 数据绑定 1. Vue中有2种数据绑定的方式: 2. 响应式原理 el 与 data 的两种写法 二、 MVVM模型 三、 数据代理 1.回顾Object defineproperty方法 2. 何为数据代理 3.Vue中的数据代理 四、 事件处理 1.事件的基本使用: 2. Vue中的事…...
Python数据类型-dict
Python数据类型-dict 字典是Python中一种非常强大且常用的数据类型,它使用键-值对(key-value)的形式存储数据。 1. 字典的基本特性 无序集合:字典中的元素没有顺序概念可变(mutable):可以动态添加、修改和删除元素键必须唯一且不可变&…...
win10之mysql server 8.0.41安装
一 mysql server 下载 官网下载地址页面 https://dev.mysql.com/downloads/mysql/二 免装版使用步骤 1 解压 下载完成后,解压文件夹,如下所示: 2 执行安装命令 D:\soft\mysql\mysql-8.0.41-winx64\mysql-8.0.41-winx64\bin>mysqld --install Service successfully in…...
解决Oracle PL/SQL中“表或视图不存在“错误的完整指南
解决Oracle PL/SQL中"表或视图不存在"错误的完整指南 前言问题概述根本原因分析一、 编译时与运行时验证差异二、权限问题三、 Schema命名问题 实际案例演示案例1:动态分表查询案例2:权限不足的场景 实用排查步骤排查流程图最佳实践建议解决方…...
从实用的角度聊聊Linux下文本编辑器VIM
本文从实用的角度聊聊Vim的常用命令。何为实用?我举个不实用的例子大家就明白了,用vim写代码。;) “vim是从 vi 发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用,和Emacs并列成…...
MySQL的进阶语法8(SQL优化——insert、主键、order by、group by、limit、count和update)
目录 一、插入数据 1.1 insert 1.2 大批量插入数据 二、主键优化 2.1 数据组织方式 2.2 页分裂 2.2.1 主键顺序插入效果 2.2.2 主键乱序插入效果 2.3 页合并 2.4 索引设计原则 三、order by优化 3.1 执行以下两条语句(无索引) 3.2 创建索引…...
STM32F103C8T6单片机硬核原理篇:讨论GPIO的基本原理篇章1——只讨论我们的GPIO简单输入和输出
目录 前言 输出时的GPIO控制部分 标准库是如何操作寄存器完成GPIO驱动的初始化的? 问题1:如何掌握GPIO的编程细节——跟寄存器如何打交道 问题2:哪些寄存器,去哪里找呢? 问题三,寄存器的含义ÿ…...
FreeRTOS源码下载分享
FreeRTOS源码下载分享 官网下载太慢了,分享下FreeRTOSv202411 FreeRTOSv202411.00.zip 链接: https://pan.baidu.com/s/1P4sVS5WroYEl0WTlPD7GXg 提取码: g6aq...
PyArrow 核心技术与应用:高效数据处理与跨生态集成实践
Apache Arrow 作为列式内存数据格式的行业标准,其 Python 接口 PyArrow 正在重塑数据科学生态。本文深入解析 PyArrow 的核心计算能力,涵盖统计函数、分组聚合、窗口操作及跨库集成,通过完整代码示例演示如何利用其高性能特性优化数据处理流程…...
机试题——PCB印刷电路板布线
题目描述 在 PCB 印刷电路板设计中,器件之间的连线需要避免线路的阻抗值增大,而且器件之间还可能存在其他干扰源。为了简化问题,我们将电路板简化为一个 ( M * N ) 的矩阵,每个位置(单元格)的值表示其源干…...
数据化管理(一)---什么是数据化管理
目录 一、什么是数据化管理1.1 “聪明”的销售人员1.2 数据化管理的概念1.3 数据化管理的意义1.4 数据化管理的四个层次1.4.1 业务指导管理1.4.2 营运指导管理1.4.3 经营策略管理1.4.4 战略规划管理 1.5 数据化管理流程图1.5.1 分析需求1.5.2 收集数据1.5.3 整理数据1.5.4 分析…...
Android 10.0 通过广播控制systemui状态栏动态显示和隐藏功能实现
1.前言 在10.0的系统rom定制化开发中,在某些特定的产品开发中,需要通过接口来控制系统状态栏的显示和隐藏, 所以就需要了解systemui状态栏的显示构造过程,然后通过相关接口来显示和隐藏状态栏,接下来就来 实现相关的功…...
Linux服务器安装MinerU
安装MinerU 为了确保项目的稳定性和可靠性,我们在开发过程中仅对特定的软硬件环境进行优化和测试。这样当用户在推荐的系统配置上部署和运行项目时,能够获得最佳的性能表现和最少的兼容性问题。 这里我们以基础的 [[Linux服务器部署PaddleX实战教程]] 使…...
深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本
前引:屏幕前的你还在AI智能搜索框这样搜索吗?“这道题怎么写”“苹果为什么红”“怎么不被发现翘课” ,。看到此篇文章的小伙伴们!请准备好你的思维魔杖,开启【霍格沃茨模式】,看我如何更新秘密的【知识炼金…...
Vite 内联 CSS 和 JS 的解决方案
使用 vite-plugin-singlefile(推荐) 这个插件专门用于将整个 Vite 应用打包成单个 HTML 文件,内联所有 JS 和 CSS。 安装 pnpm i vite-plugin-singlefile -D配置 vite.config.js import { defineConfig } from vite import { viteSingleF…...
致敬生物信息学先驱:玛格丽特·戴霍夫(Margaret Dayhoff,1925-1983)
李升伟 编译 社论 发布于:2025年3月11日 《自然-计算科学》第五卷 第187页(2025年) 在玛格丽特戴霍夫(Margaret Dayhoff,1925-1983)百年诞辰之际,我们聚焦这位先驱在生物信息学领域留下的不朽…...
Knife4j文档请求异常 空指针
打开swagger文档报空指针异常 java.lang.NullPointerException: nullat springfox.documentation.oas.mappers.SchemaMapper.model(SchemaMapper.java:97)at springfox.documentation.oas.mappers.SchemaMapper.mapModel(SchemaMapper.java:85)at springfox.documentation.oas…...
笔记2——网络参考模型
一、OSI参考模型: 应用层: 报文 给应用程序提供接口 表示层: 进行数据格式的转换 会话层: 在通讯双方之间建立、管理和终止会话 传输层: 数据段;建立、维护、取消一次端到端的数据传输过程;控制…...
Spring AOP + Redis缓存设计实战:基于注解的优雅三防方案(击穿/穿透/雪崩)
文章目录 摘要 正文一、缓存设计的痛点与破局二、核心代码拆解:四层防御设计1. 注解驱动(ZywCacheable)2. 缓存击穿防护:双重检查锁3. 缓存穿透防护:空值标记4. 缓存雪崩防护:TTL随机算法 三、生产环境最佳…...
洛谷题单3-P5720 【深基4.例4】一尺之棰-python-流程图重构
题目描述 《庄子》中说到,“一尺之棰,日取其半,万世不竭”。第一天有一根长度为 a a a 的木棍,从第二天开始,每天都要将这根木棍锯掉一半(每次除 2 2 2,向下取整)。第几天的时候木…...
jdk21新特性详解使用总结
jdk21新特性详解总结 1.StringBuilder和StringBuffer新增了一个repeat方法 /*** Java 21的StringBuilder和StringBuffer新增了一个repeat方法*/public static void repeatStr(){var sbnew StringBuilder().repeat("*",10);System.out.println(sb);}运行结果如下&…...
解码 collections.Counter - 频率统计的利器
文章目录 前言一、什么是 collections.Counter?二、 基本用法:从创建到访问2.1 创建 Counter 对象2.2 访问计数三、 核心功能:更新与排序3.1 更新计数3.2 获取常见元素四、高级用法:数学运算与转换4.1 数学运算4.2 类型转换五、 实际应用:Counter 的威力5.1 词频统计5.2 在…...
Mysql基础笔记
# 1.SQL数据类型 可以去这篇文章看看: 最全 SQL 字段类型(4种)、属性(6种)总结:https://blog.csdn.net/weixin_45654582/article/details/119157403 ### 一.整数类型 ### 二.小数类型(2种) 1、浮点型:…...
HttpClient-03.入门案例-发送POST方式请求
一.发送POST方式请求 编写代码: 1.创建一个HttpClient对象 2.创建一个HttpGet请求 3.发送http的get请求并获得响应对象 4.通过发送GET请求获取的CloseableHttpResponse响应对象来获取状态码以及响应数据 package com.sky.test;import com.alibaba.fastjson.JS…...
Oracle数据库数据编程SQL<3.6 PL/SQL 包(Package)>
包是Oracle数据库中一种重要的PL/SQL程序结构,它将逻辑相关的变量、常量、游标、异常、过程和函数组织在一起,提供了更好的封装性和模块化。在大型项目中,可能有很多模块,而每一个模块又有自己的存过、函数等。而这些存过、函数默…...
每日一题---买卖股票的最好时机(一)、(二)
目录 买卖股票的最好时机(一) 一、题目链接:买卖股票的最好时机(一)_牛客题霸_牛客网 二、解题思路 三、代码实现 买卖股票的最好时机(二) 一、题目链接:买卖股票的最好时机(二)_牛客题霸_牛客网 编辑 二、解题思路 …...
XSS漏洞的分类解释和演示实验
XSS漏洞:跨站脚本攻击(cross site scripting),为了不和CSS混淆而改名。攻击者网web插入恶意script代码,当用户浏览页面时,嵌入的代码会被执行。 危害:盗取各类用户,强制发送电子邮件,网站挂马等…...
【Pandas】pandas DataFrame info
Pandas2.2 DataFrame Attributes and underlying data 方法描述DataFrame.index用于获取 DataFrame 的行索引DataFrame.columns用于获取 DataFrame 的列标签DataFrame.dtypes用于获取 DataFrame 中每一列的数据类型DataFrame.info([verbose, buf, max_cols, …])用于提供 Dat…...
JP1 Systemwalker 和 unirita的A-AUTO制品对比
以下是 JP1 SystemWalker(日立) 与 Unirita A-AUTO 的对比分析。两者均为日本企业开发的IT运维自动化工具,但在功能定位、技术架构和适用场景上存在显著差异: 1. 产品背景与市场定位 维度JP1 SystemWalkerUnirita A-AUTO开发商日…...
探索鸿蒙操作系统:迎接万物互联新时代
# 探索鸿蒙操作系统:迎接万物互联新时代 在科技飞速发展的当下,万物互联的时代浪潮正席卷而来。在这个全新的时代背景下,移动应用开发领域面临着前所未有的挑战,同时也迎来了诸多机遇。而鸿蒙操作系统(HarmonyOS&…...
NOIP2010提高组.引水入城
*前置题目 901. 滑雪 #include <iostream> #include <algorithm> #include <cstring>using namespace std;const int N 310, INF 0x3f3f3f3f; const int dx[4] {0, -1, 0, 1}, dy[4] {1, 0, -1, 0};int n, m, h[N][N]; int f[N][N]; int ans;int dfs(i…...
NLP高频面试题(二十九)——大模型解码常见参数解析
在大语言模型的实际应用中,如何更有效地控制文本生成的质量与多样性,一直是热门研究话题。其中,模型解码(decode)策略至关重要,涉及的主要参数包括 top_k、top_p 和 temperature 等。本文将详细介绍这些常见…...
【AI产品分享】面向图片的原始位置翻译功能
1. 背景 在撰写文字材料时,往往需要配套图像以增强表达效果。然而,有时自己绘制的图可能达不到理想的质量,而在其他文献材料中却能发现更清晰、直观的示例。希望在“站在巨人的肩膀上”优化自己的图像时,通常希望在保留原始图像的…...
为什么要为 REST API 添加认证
在不断发展的 Web 服务领域,REST API 在各种软件系统之间的通信中扮演着至关重要的角色。然而,强大的功能也伴随着巨大的责任。确保敏感数据的安全性和通信的可靠性是至关重要的。这时,认证就显得尤为重要。通过使用认证,我们可以…...
AI 数字人短视频数字人源码部署揭秘:开启虚拟内容创作新纪元
在当下短视频盛行的时代,AI 数字人短视频以其独特的魅力吸引着大众的目光。虚拟偶像在舞台上活力四射,电商平台中数字人不知疲倦地推荐产品,这些令人瞩目的表现背后,源码的部署起着至关重要的作用。它如同幕后的神奇工匠ÿ…...
佳能imageRUNNER 2206N基本参数及管理员密码
基本参数: 产品类型 激光数码复合机 颜色类型 黑白 涵盖功能 复印/打印/扫描 速度类型 低速 最大原稿尺寸 A3 复印/打印方式 激光静电转印方式 感光材料 OPC 显影系统 干式单组分显影 定影…...
【Linux篇】探索进程地址空间:计算机背后的虚拟世界
进程地址空间的奥秘:让你理解程序如何在计算机中生存 一. 程序地址空间1.1 基本概念1.2 虚拟内存管理1.3 为什么存在虚拟地址空间1.3.1 意义 2. 最后 本文将介绍进程地址空间的基本概念与结构,帮助读者理解操作系统如何管理和分配内存。进程地址空间指的…...
Docker部署sprintboot后端项目
创建Docker网络 docker network create icjs 部署Redis docker run -d \--network icjs \--name redis \-p 6379:6379 \redis:latest数据持久化 docker run --restartalways --network icjs -p 6379:6379 --name redis -v /opt/docker/redis/redis.conf:/etc/redis/redis.c…...
1.4 基于模拟退火改进蛇算法优化VGG13SE网络超参数的故障诊断模型
本博客来源于CSDN机器鱼,未同意任何人转载。 更多内容,欢迎点击本专栏,查看更多内容。 目录 0 引言 1 改进原理 2 本文改进方法 3 改进蛇优化VGG13SE的故障诊断模型 4 结语 0 引言 在【博客】中,我们采用了蛇算法来对VGG1…...
Vue + Scss项目中实现自定义颜色主题的动态切换
当时面试的时候遇到面试官问的一个问题如何实现自定义颜色主题切换,当时我做的只是elementUIPlus提供的暗黑和默认主题切换 theme.scss // 增加自定义主题类型 $themes: (light: (/* 原有配置保持不变 */),dark: (/* 原有配置保持不变 */),custom: () // 空映射…...
C#实现HiveQL建表语句中特殊数据类型的包裹
用C#实现搜索字符串中用’(‘和’)‘包裹的最外层的里面里面的字符串,将里面的记录按一个或多个空格、换行或tab,或者是它的在一起的组合作为分隔,分隔出多个字符串组,如果组中有字符串中同时包含’<‘和’>’,则…...