【计算机和UNIX汇编原理④】——指令系统(上)【标志寄存器 立即寻址 寄存器寻址 直接/寄存器/基址/变址寻址 万字总结】


🚀



感觉越来越能 “画” 了… 🍋

文章中穿插了一些个人的理解,特别是绿色字体部分,如有笔误,烦请留言。

上一篇文章链接: 《【计算机与汇编原理③】——80X86微处理器》.
下一篇文章链接: 《【计算机和汇编原理⑤】——指令系统(下)【 2万5千字总结 】》.


一、概述


  ● 指令:通知 CPU 执行某种操作的 “命令”。CPU全部指令的集合,称为指令系统。

  我们在编写程序的时候,都是一行一行地编写的,每一行一般是个语句,而一条语句一般包含多条指令。比如说,我要执行 “A = B + C;” 这条语句,那么我得依次执行:① 取指令(取数据C)。 ② 取指令(取数据B)。③ 加指令(B和C相加)。④ 放指令(将结果送到A)

  ● 指令的书写格式
    ◆ 目标指令(机器指令):二进制形式的序列 (即:一串0、1代码)。注意:硬件只能识别、存储、运行目标指令。
    ◆ 符号指令:字符串形式的序列 (即用规定的操作码和操作数助记符,按照规定的书写格式书写的指令。

  ● 键盘等外设的出现,为简化指令的输入带来了方便。同时,为了便于记忆和输入,在人机交互中,一般不再直接输入机器指令,而是输入对应的采用指令助记符描述的符号指令。

  ● 指令的组成:(大多数指令)由操作码和操作数两个部分组成。

在这里插入图片描述

  ◆ 操作码:通知CPU执行什么操作 (唯一)
  ◆ 操作数:指令的操作对象 (一个或多个)


  ● 举几个关于指令的栗子:

在这里插入图片描述
  ◆ 说明:
    ① 第一个操作 “1234H → AX” 的意思:将地址为 “1234H” 的寄存器里面的数据,传送到 CPU里面的通用寄存器 EAX 的低 16 位里面去。
    ② “80486符号指令” 这一栏就是程序员敲的代码,而 “80486机器指令” 就是计算机能读得懂的数据。
    ③ MOV(MOVE的缩写):传送。ADD: 加。SUB: 减。RET: RETURN 返回。


  ● CPU 只能识别、存储、运行目标指令,而用机器指令编程非常困难。于是早期的专家们发明了符号指令,再经过某种特殊的软件把符号指令 → 机器指令。目标程序的生成的流程图如下:

在这里插入图片描述

  ● 指令长度:指令在存储器中占用的字节数称为指令长度。86x86指令长度 (指机器指令长度) 为1~16 字节。

  ● 指令地址:存放指令第一字节的内存单元地址。单字节指令占用1个内存单元,多字节指令占用连续的内存单元,。

  ● 指令存放:指令存放在内存中时,先存放操作码,再存放操作数。多字节操作数连续存放。顺序依据小端法原则,即: 低位字节存放在低地址单元,高位字节存放在相邻的高地址单元。

  如:12345H单元中有一条指令 “ MOV AX,6789H ”,则它在内存中的形式如下图所示:

在这里插入图片描述


  ● 符号指令的书写格式

在这里插入图片描述

  ◆ 说明:
    ① 操作码:表示 CPU 执行的操作。
    ② 操作数:指令执行时的操作对象 (一个或多个)。
    ③ 标号:以字母开头,后面可以跟字母、数字或下划线,但长度必须 ≤ 31个字符,标号又称符号地址,代表该指令的逻辑地址。可有可无,设置是为了程序的转向。
    ④ 注解:以 “ ;” 开头,不执行,打印程序清单时照原样打印,“系统保留字”不能做标号。

  ◆ 举个栗子如下:
     N E X T :         A D D    A X , B X        ; A X + B X → A X NEXT:\,\,\,\,\,\,\,ADD\,\,AX,BX\,\,\,\,\,\,;AX+BX → AX NEXT:ADDAX,BX;AX+BXAX
                                     I N C        S I                      ; S I + 1 → S I \,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,INC\,\,\,\,\,\,SI\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,;SI+1 → SI INCSI;SI+1SI



二、寻址方式(这一章的难点、重点)


  ● 寻址:形成操作数地址码的过程。操作数是指令的操作对象,寻址方式就是在指令中,使用特定的助记符 (地址表达式),告知 CPU 如何计算出操作数的地址。寻址方式只有针对操作数而言才有意义。

  ● 操作数的分类
    ① 立即数:操作数包含在指令中。
    ② 寄存器操作数:操作数存放在 CPU 的某个寄存器中。
    ③ 存储器操作数(内存操作数) :操作数存放在存储器中。
    ④ I/O 端口操作数:操作数存放在 I/O 端口中。

  ● 本章只讲述前 3 种操作数对应的寻址方式,包含以下 3 类共计 7 种寻址方式:
    ① 立即寻址方式:获得立即数
    ① 寄存器寻址方式:获得寄存器操作数
    ① 存储器寻址方式:获得存储器操作数(内存操作数)


1、立即寻址

  ● 立即寻址:操作数包含在本条指令中,是指令的一部分,和指令操作码一起存放在代码段中。CPU 完整地取出该条指令,也就获得了操作数。流程如图所下:

在这里插入图片描述


  ◆ 举个栗子如下:
  例: M O V D X , 1234 H MOV \quad DX,1234H MOVDX,1234H

在这里插入图片描述
  ◆ 说明:
    ① “DX” 是目标操作数,“1234H” 是源操作数
    ② 对于“1234H” 这个源操作数,就是立即寻址,因为这个操作数就在指令里面。
    ② 而对于 “AX” 这个目标操作数,是寄存器寻址,后面再讲。

  ◆ 还有些例子如下:
    ① M O V E A X , 12345678 H MOV \quad EAX,12345678H MOVEAX,12345678H
    ② M O V B L , 10101010 B ; A A H → B L MOV \quad BL,10101010B \quad\quad;AAH → BL MOVBL,10101010B;AAHBL
    ③ M O V C L , – 4 ; F C H → C L MOV \quad CL, – 4 \quad\quad;FCH →CL MOVCL,4;FCHCL
    ④ M O V D L , ’ A ’ ; 41 H → D L MOV \quad DL,’A’ \quad\quad;41H →DL MOVDL,A;41HDL
    ⑤ A D D A L , 0 C 8 H ADD \quad AL,0C8H ADDAL,0C8H
    ⑥ M O V S I , 3 ∗ 5 ; 15 → S I MOV \quad SI,3*5 \quad\quad;15 →SI MOVSI,35;15SI

  ● 上例中 源操作数 均为为立即寻址, 立即数书写规定:
    ① 立即数以数字开头。若以A~F开头的 16 进制数,必须有个前缀 0。
    ② 立即数的数制用后缀表示,B 表示二进制,H 表示十六进制, D 或缺省表示十进制,单引号括起来的字符编译成相应的 ASCII 码 。
    ③ 可以用 “+、– 、* 、/ ” 组成立即数表达式
    ④ 程序员可以按自己的习惯书写立即数。各种合法的立即数经汇编后,一律自动转换成等值的二进制数,负数用补码表示。


2、寄存器寻址

  ● 寄存器寻址:操作数在 CPU 的某个寄存器中,符号指令中直接写出寄存器名称。流程如图所下:

在这里插入图片描述


  ◆ 举个栗子如下:
  例: M O V D X , A X MOV \quad DX,AX MOVDX,AX

在这里插入图片描述
  ◆ 说明:
    ① “DX” 是目标操作数,“AX” 是源操作数
    ② “AX” 和 “DX” 这两个操作数都在寄存器里面,都是寄存器寻址。


  ◆ 再把原先的例子搬下来:
    ① M O V E A X , 12345678 H MOV \quad EAX,12345678H MOVEAX,12345678H
    ② M O V B L , 10101010 B ; A A H → B L MOV \quad BL,10101010B \quad\quad;AAH → BL MOVBL,10101010B;AAHBL
    ③ M O V C L , – 4 ; F C H → C L MOV \quad CL, – 4 \quad\quad;FCH →CL MOVCL,4;FCHCL
    ④ M O V D L , ’ A ’ ; 41 H → D L MOV \quad DL,’A’ \quad\quad;41H →DL MOVDL,A;41HDL
    ⑤ A D D A L , 0 C 8 H ADD \quad AL,0C8H ADDAL,0C8H
    ⑥ M O V S I , 3 ∗ 5 ; 15 → S I MOV \quad SI,3*5 \quad\quad;15 →SI MOVSI,35;15SI

  ● 上例 目标操作数 (左边)均为为寄存器寻址,而 源操作数 (右边)均为为立即寻址


3、存储器操作数寻址方式

  ● 存储器操作数寻址方式是最复杂的,它又分成 5 个小类。

  ● 在读写内存操作数之前,CPU必须知道相关存储单元的物理地址。但由于 CPU 对存储器采用分段管理, 因此在指令格式中 只能写出存放操作数所在内存单元的 “逻辑地址”。

  存储单元逻辑地址表达式的一般形式:

在这里插入图片描述

  ● 实模式下,物理地址 = 段寄存器 × 24 + 偏移地址【后面细讲】
  程序员的责任仅在于正确的书写逻辑地址表达式,然后由 CPU 自动运算以求出物理地址。


3.1 直接寻址 ⭐️

  ● 直接寻址的流程如图所下:

在这里插入图片描述

  ① 地址表达式的格式1:“ 段寄存器:[偏移地址] ”
    如: M O V A L , E S : [ 2 C H ] ; 从 E S ( 附 加 段 ) 且 偏 移 地 址 为 2 C H 的 单 元 取 数 → A L MOV \quad AL, ES:[2CH] \quad;从ES(附加段)且偏移地址为2CH的单元取数→AL MOVAL,ES:[2CH];ES()2CHAL
    如: M O V A X , D S : [ 1234 H ] ; 从 D S ( 数 据 段 ) 且 偏 移 地 址 为 1234 H 的 单 元 取 数 → A X MOV \quad AX, DS:[1234H] \quad ;从DS(数据段)且偏移地址为1234H的单元取数 → AX MOVAX,DS:[1234H];DS()1234HAX
  注:这种格式很少使用,通常情况下,程序员并不知道某单元的偏移地址。【常用下面这种格式】

  ② 地址表达式的格式2:“ 段寄存器:变量名 ”,即用变量名来代表存储单元的有效地址


  ◆ 举个采用第一种地址表达式的栗子如下:
    例: M O V A X , D S [ 1234 H ] MOV \quad AX,DS[1234H] MOVAX,DS[1234H]

在这里插入图片描述

  ◆ 举个采用第二种地址表达式的栗子如下:
    首先假设取名为 “XX” 的DS(数据段) 的内容为 11H
    其次假设取名为 “YY” 的ES(附加段) 的内容为 2233H
     M O V A L , D S : X X ( 或 M O V A L , X X ) ; 取 名 为 “ X X ” 的 D S ( 数 据 段 ) 的 内 容 → A L MOV \quad AL, DS:XX (或 MOV \quad AL, XX) \quad\quad;取名为 “XX” 的DS(数据段)的内容→AL MOVAL,DS:XX(MOVAL,XX);XXDS()AL
     M O V A X , E S : Y Y ( 或 M O V A X , Y Y ) ; 取 名 为 “ Y Y ” 的 E S ( 附 加 段 ) 的 内 容 → A X MOV \quad AX, ES:YY (或 MOV \quad AX, YY) \quad\quad;取名为 “YY” 的ES(附加段)的内容→AX MOVAX,ES:YY(MOVAX,YY);YYES()AX

  ◆ 说明:
    ① 汇编语言允许为某单元起一个 “名字”,这个名字就称为该单元的 “变量名”,经汇编之后,变量名有段基址和偏移量两种属性
    ② 由于变量名是唯一的,程序中不能有重复的变量名。
    ③ “段寄存器:”可以省略不写。


3.2 寄存器间接寻址 ⭐️

  ● 寄存器间接寻址 又称 “间接寻址”、“间址”。
  ● 间接寻址操作数在内存单元中,该单元的段基址在段寄存器中,而偏移地址在间址寄存器中,CPU首先找到这两者,然后进行地址计算,得到最终的物理地址。

  间接寻址与直接寻址的不同,就在于多了一个 “间接寄存器” ,它的操作数中没有直接 “放” 偏移量,而需要 CPU 去间接寄存器把那个偏移量找出来。

  ● 间接寻址的地址表达式:“ 段寄存器:[间址寄存器] ”
  某单元的物理地址 = 段寄存器内容 × 24 + 间址寄存器

  ● 访问约定的逻辑段,间接寻址的地址表达式可简化为:“ [间址寄存器] ”
  某单元的物理地址 = 约定的段寄存器内容 × 24+ 间址寄存器

  ● 间址寄存器和约定访问的逻辑段的图表:

间址寄存器约定访问的逻辑段适用范围
BPSS(堆栈段)16位寻址方式
BX、SI、DIDS(数据段)16位寻址方式
EBP、ESPSS(堆栈段)32位寻址方式
EAX、EBX、ECX、EDX、ESI、EDIDS(数据段)32位寻址方式

  ◆ 举个栗子:
  设取名为 “BUF” 的数据段的字节单元内容为 55H,需要取出该数 → AL

  ① 解法1:用 BX 间址【在表格中的第三排】
     M O V A X ,   B U F 数 据 段 的 段 基 址 MOV \quad AX,\,BUF数据段的段基址 MOVAX,BUF
     M O V D S ,   A X MOV \quad DS,\,AX MOVDS,AX
     M O V B X ,   B U F 单 元 的 有 效 地 址 ; 有 效 地 址 也 称 为 偏 移 地 址 MOV \quad BX,\,BUF单元的有效地址\quad \quad;有效地址也称为偏移地址 MOVBX,BUF;
     M O V A L ,   D S : [ B X ] ; A L = 55 H MOV \quad AL,\,DS:[BX] \quad \quad\quad \quad\quad \quad\quad ;AL=55H MOVAL,DS:[BX];AL=55H
  由于 BX 为间址寄存器,且为约定访问的是数据段,因此 “DS:” 可省。故最后一行代码等价于: “ M O V A L ,   [ B X ] MOV \quad AL ,\, [BX] MOVAL,[BX]

  ② 解法2:用 BP 间址【在表格中的第二排】
     M O V A X ,   B U F 数 据 段 的 段 基 址 MOV \quad AX ,\, BUF数据段的段基址 MOVAX,BUF
     M O V D S ,   A X MOV \quad DS ,\, AX MOVDS,AX
     M O V B P ,   B U F 单 元 的 有 效 地 址 MOV \quad BP ,\, BUF单元的有效地址 MOVBP,BUF
     M O V A L ,   D S : [ B P ] ; A L = 55 H MOV \quad AL ,\, DS:[BP] \quad\quad\quad\quad\quad\quad\quad;AL=55H MOVAL,DS:[BP];AL=55H
  由于 BP 为间址寄存器,但约定访问的是堆栈段(不是数据段),因此 “DS:” 不可省,即不能写成: “ M O V A L ,   [ B P ] MOV \quad AL ,\, [BP] MOVAL,[BP]

  ② 解法3:用变量名直接寻址
     M O V A X ,   B U F 数 据 段 的 段 基 址 MOV\quad AX,\,BUF数据段的段基址 MOVAX,BUF
     M O V D S ,   A X MOV\quad DS,\,AX MOVDS,AX
     M O V A L ,   B U F ; A L = 55 H MOV\quad AL,\, BUF\quad\quad\quad\quad\quad\quad\quad \quad\quad ;AL=55H MOVAL,BUF;AL=55H


3.3 基址寻址 ⭐️

  ● 在基址寻址中,有效地址(即偏移地址)由两部分组成。一部分存放在基址寄存器中,另一部分为常量 。

  基址寻址与间接寻址的不同,就在于偏移地址的计算复杂了点。此时 CPU 不能去间接寄存器直接找出偏移地址,而是去基址寄存器把 “基偏移地址” 找出来,再把这 “基偏移地址” 和 “位移量” 相加,间接地得到偏移地址。

  ① 基址寻址的地址表达式 1:“ 段寄存器:[基址寄存器 + 位移量] ”
  物理地址 = 段寄存器内容 × 24 + 基址寄存器 + 位移量

  ② 基址寻址的地址表达式 2:“ [基址寄存器 + 位移量] ”。使用条件:访问约定的逻辑段。
  物理地址 = 约定的段寄存器内容 × 24 + 基址寄存器 + 位移量

  ● 基址寄存器和约定访问的逻辑段:

基址寄存器约定访问的逻辑段适用范围
BPSS(堆栈段)16位寻址方式
BXDS(数据段)16位寻址方式
EBP、ESPSS(堆栈段)32位寻址方式
EAX、EBX、ECX、EDX、ESI、EDIDS(数据段)32位寻址方式

  ◆ 举个栗子:
  设数据段 BUF 单元依次有: 78 H , 56 H , 34 H , 12 H 78H,56H,34H,12H 78H,56H,34H,12H,现在需要进行一些访问。
  则: M O V A X , 数 据 段 段 基 址 MOV AX , 数据段段基址 MOVAX,
     M O V D S ,   A X MOV \quad DS ,\, AX MOVDS,AX
     M O V B X ,   B U F 单 元 有 效 地 址 MOV \quad BX ,\, BUF单元有效地址 MOVBX,BUF
     M O V D H ,   [ B X + 1 ] ; D H = 56 H MOV \quad DH ,\, [BX+1] \quad \quad \quad\quad;DH=56H MOVDH,[BX+1];DH=56H
     M O V D X ,   [ B X + 2 ] ; D X = 1234 H MOV \quad DX ,\, [BX+2] \quad \quad \quad \quad;DX=1234H MOVDX,[BX+2];DX=1234H

在这里插入图片描述
  注:DH 是 EDX 的高 8 位,所以只能送入一个 16 进制数。 DX 是 EDX 的低 16 位,所以能送入两个 16 进制数。


3.4 变址寻址 ⭐️

  ● 在变址寻址中,有效地址(即偏移地址)由两部分组成。一部分存放在变址寄存器中(可能这部分还要乘以一个系数),另一部分为常量 。

  变址寻址与基址寻址的不同,就在于偏移地址的计算 复杂了点。此时 CPU 不去基址寄存器,而是去变址寄存器。

  ● ① 有比例因子的变址寻址的表达式:“ 段寄存器:[比例因子 × 变址寄存器 + 位移量] ”
  物理地址 = 段寄存器 × 24 + 比例因子 × 变址寄存器 + 位移量

  ● ② 没有比例因子的变址寻址的表达式:“ 段寄存器:[变址寄存器 + 位移量] ”
  访问约定的逻辑段可简化为 : [变址寄存器 + 位移量]
  物理地址 = 约定的段寄存器 × 24 + 变址寄存器 + 位移量

  ● 变址寄存器与约定访问的逻辑段:

变址寄存器约定访问的逻辑段适用范围
SI、DIDS(数据段)无比例因子,且16位寻址方式
EBPSS(堆栈段)有比例因子,且32位寻址方式
EAX、EBX、ECX、EDX、ESI、EDIDS(数据段)有比例因子,且32位寻址方式

  ● 说明:比例因子只能是1、2、4、8
    因此 “ M O V A L , [ 8 × S I + 15 ] ; MOV AL, [8\times SI+15]; MOVAL,[8×SI+15]; ” 是非法的,因为 16 位的寻址方式不能使用比例因子。(即 SI 不行,但 ESI 可以)
    比例因子错了的非法指令: M O V A L ,   [ 10 × E S I + 5 ] MOV \quad AL ,\, [10\times ESI+5] MOVAL,[10×ESI+5]
    访问附加段的正确指令: M O V A L ,   E S : [ S I ] MOV \quad AL ,\, ES:[SI] MOVAL,ES:[SI]
    访问数据段的正确指令: M O V A L ,   [ S I ] MOV \quad AL , \,[SI] MOVAL,[SI]


3.5 基址加变址寻址 ⭐️

  ● 在基址加变址寻址中,有效地址(即偏移地址)由三部分组成。第一部分存放在基址寄存器中,第二部分存放在变址寄存器,第三部分为常量(位移量)。

  基址加变址寻址,简单来说,就是 “基址寻址” 与 “变址寻址” 的结合。

  ① 有比例因子的基址加变址的地址表达式:“ 段寄存器:[基址寄存器 + 比例因子 × 变址寄存器 + 位移量] ”

  ② 有比例因子且有访问约定逻辑段的地址表达式:“ [基址寄存器 + 比例因子 × 变址寄存器 + 位移量] ”

  ③ 无比例因子基址加变址的地址表达式:“ 段寄存器:[基址寄存器+变址寄存器+位移量]

  ④ 无比例因子且有访问约定逻辑段的地址表达式:“ [基址寄存器+变址寄存器+位移量] ”

  ● 基址加变址寻址的要求:基址寄存器和变址寄存器必须都是 16 位或都是 32 位,否则(16位寻址和32位寻址混合使用)是非法指令。

  ● 默认的段寄存器不一致,这样的组合虽然是合法,但容易出错。如:[BP+SI],[BP+DI]
  ● BP 约定的逻辑段为堆栈段,而 SI、DI 约定的逻辑段为数据段,它们组合之后约定访问的逻辑段是堆栈段,但这样的组合最好要加段前缀。

  例: M O V A L ,   [ B X + S I + 0250 H ] MOV\quad AL,\,[BX+SI+0250H] MOVAL,[BX+SI+0250H]



三、标志寄存器(这一节也很重要)

在这里插入图片描述
  ● 80486 标志寄存器为 32 位,实际只使用 15 位。
  ● 15 位标志分为两类:状态标志和控制标志。
  ● 状态标志记录了当前指令执行后的状态信息。
  ● 控制标志用来控制微处理器操作,本节首先介绍 6 种状态标志。

  ① C 标志——进位/借位标志
    字节的加/减:最高位(D7)产生进位/借位时 C 标志置1,否则置0
    的加/减:最高位(D15)产生进位/借位时 C 标志置1,否则置0
    双字的加/减:最高位(D31)产生进位/借位时 C 标志置1,否则置0

  ② A 标志——辅助进位/辅助借位标志
    字节、字、双字的加/减,D3 位产生进位/借位时 A 标志置1,否则置0

  ③ S 标志——符号标志
    字节运算后,若结果的最高位 D7 位为1,S标志置1,否则置0
    运算后,若结果的最高位 D15 位为1,S标志置1,否则置0
    双字运算后,若结果的最高位 D31 位为1,S标志置1,否则置0

  ④ Z 标志——结果标志
    运算结果为全0时,Z标志置1,否则置0

  ⑤ P 标志——奇偶标志(实际上是偶标志)
    运算结果中,最低的 1 个字节中 “1” 的个数为偶数时(没有“1”也是偶数),P标志置1,否则置0

  ⑥ O 标志——溢出标志
    运算结果产生溢出时,则 O 标志置1,否则置0

  ● 关于 “ 溢出的几个概念、CPU如何判断溢出、程序员如何判断溢出(有符号数/无符号数) ” 的相关知识,可详见这篇:
《计算机基础【原码 补码 反码 移码 BCD码 溢出 进位…】》: https://blog.csdn.net/Wang_Dou_Dou_/article/details/120054864?spm=1001.2014.3001.5501.

  ◆ 举个栗子:执行下列指令后,AL = ?,标志寄存器 A、C、O、P、S、Z 分别为何值?(必考)

     M O V A L ,   0 C 8 H MOV \quad AL,\,0C8H MOVAL,0C8H
     A D D A L ,   0 C 8 H ADD \quad AL,\,0C8H ADDAL,0C8H

在这里插入图片描述
  最终结果为 AL = 90H。如果 C8H 为无符号数(值 = 200),则有溢出。如果 C8H 为有符号数(值 = -56),则无溢出。 这 6 个标志中,C、O、P、S、Z 可为程序的转移提供测试条件。



四、参考附录:

[1] 《微型计算机原理与接口技术(慕课板)》
清华大学出版社

[2] 《汇编语言程序设计(第2版)》

上一篇文章链接: 《【计算机与汇编原理③】——80X86微处理器》.

下一篇文章链接: 《【计算机和汇编原理⑤】——指令系统(下)【 2万5千字总结 】》.


PPT制图不易,多多支持 🚀 🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一支王同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值