流水账(CPU设计实战)——lab9

本文详细介绍了CPU设计中的Lab9,涵盖了五级流水线的各个阶段,包括IF、ID、EXE、MEM和WB。讨论了接口信号、时序设计以及特殊指令处理,如跳转指令和乘法除法单元。还提到了中断优先级、ExcCode编码、BadVAddr寄存器的工作原理以及中断处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Lab9 V6.0

版本控制

版本描述
V0Lab3
V1.0Lab3 相对V0变化: 修改了文件名,各阶段以_stage结尾(因为if是关键词,所以module名不能叫if,遂改为if_stage,为了统一命名,将所有module后缀加上_stage) 删除了imm_sign信号(默认对立即数进行有符号数扩展) 由于对sw指令进行了重新理解:无论如何都是需要将rt_data传递给EXE阶段,故将部分译码逻辑进行后移至EXE阶段,避免id_to_exe_data总线过于庞大 将ins_shmat剔除出id_to_exe_data,因为imm包括ins_shamt 对信号进行重命名(例如在ID阶段有个信号叫rf_we,最终要传递给WB阶段,那么在EXE阶段,该信号叫作exe_rf_we,同理mem_rf_we,wb_rf_we),不然都叫rf_we,Debug的时候太痛苦了。
V2.0Lab4 相对V1.0的变化 引入`ifdef-`else-`endif来实现相对V1.0的代码增量 增加了旁路控制,减少流水线阻塞(因为增加了旁路,所以修改了ID、EXE、MEM的接口) 修改了ready_go命令,用于控制流水线的阻塞
V3.0Lab6(加载的是func_lab6的.coe文件,而不是func_lab5的,因为没有func_lab5这个东西) 相对V2.0的变化:电路细节变化详见:“CPU设计实战电路图”,图中Lab6的变化均以红色背景的方框框起来,并以黄色背景的“Lab6复用/新增信号”标注。本lab6.docx中,新增及修改的信号以红色标注。 删掉了ALU.v的接口,将alu_shamt合并至data_1,方便对新加指令sllv、srlv、srav的数据通路的复用 增加了ID.v中的alu_add的“或门”的输入 扩充了id_to_exe_data总线数据, 因为alu_op扩充了新的指令 添加了imm_zero_ext信号 修改了ins_R、ins_J、ins_I,因为增加了新的指令 乘法器和除法器调用vivado的IP,其周期参数化可配置设计 乘法和除法结果存放的寄存器HI/LO放在WB.v中 增加了sfr.v,用于特殊寄存器的存储 增加了mul_div.v,用于处理乘法和除法。增加了mul.v用于处理乘法,增加了divu.v用于处理无符号除法,增加了divs.v用于处理有符号除法 修改了id_to_exe_data,添加了新信号:imm_zero_ext_en 修改了id_to_exe_data,扩充了alu_op的位宽,并将alu_op调整至id_to_exe_data的最高位,方便未来扩充指令
V4.0Lab7 修改了alu_op的位宽 新增了两个bus:lw_bus、sw_bus,同时将mem_rd整合至lw_bus,将mem_we整合至sw_bus 扩大了id_to_exe_data lw_bus传递至MEM阶段结束,sw_bus传递至EXE阶段结束 修改了旁路,之前都是lw的旁路,这里将其扩充了lb、lbu、lh、lhu、lwl、lwr
V5.0Lab8 (对应第7章任务一):添加syscall例外支持 增加MTC0、MFC0、ERET指令 增加CP0寄存器Status、Cause、EPC 增加SYSCALL指令 新建SSR.v(即system registers),是ID.v的子模块 为ID、EXE、MEM、WB级增加了flush信号,用于将数据清零
V6.0添加break指令断点例外 添加地址错、整数溢出、保留指令例外 增加CP0寄存器Count、Compare、BadVAddr 增加时钟中断 增加6个硬中断 增加2个软件中断

Top顶层

接口信号

MYCPU_TOP.v(TOP

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
取指端访存接口
inst_sram_en1O指令RAM使能信号,高电平有效
inst_sram_wen4O指令RAM字节写使能信号,高电平有效
inst_sram_addr32O指令RMA读写地址,字节寻址
inst_sram_wdata32O指令RAM写数据
inst_sram_rdata32I指令RAM读数据
数据端访存接口
data_sram_en1O数据RAM使能信号,高电平有效
data_sram_wen4O数据RAM字节写使能信号,高电平有效
data_sram_addr32O数据RAM读写地址,字节寻址
data_sram_wdata32O数据RAM写数据
data_sram_rdata32I数据RAM读数据
debug信号,供验证平台使用
debug_wb_pc32O写回级(多周期最后一级)的PC,需要myCPU里将PC一路传递到写回级
debug_wb_rf_wen4O写回级写寄存器堆(regfiles)的写使能,为字节使能,如果myCPU写regfiles为单字节写使能,则将写使能扩展成4位即可
debug_wb_rf_wnum5O写回级写regfiles的目的寄存器号
debug_wb_rf_wdata32O写回级写regfiles的写数据

接口时序

略(MIPS经典五级流水线)

代码结构

MYCPU_TOP.v

|____IF.v

|____ID.v

|____RF.v(2个读端口,1个写端口)

|____SFR.v(1个读端口,2个写端口)

|____SSR.v

|____EXE.v

|____ALU.v

|____MUL_DIV.v(专门处理乘法和除法)

|____MUL.v

|____DIVU.v

|____DIVS.v

|____MEM.v

|____WB.v

|____MYCPU.h

DATA_RAM.v

IF.v(修改为IF_STAGE,因为会与关键词if冲突)

接口信号

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与TOP
inst_sram_en1ORAM使能信号,高电平有效
inst_sram_wen4ORAM字节写使能信号,高电平有效
inst_sram_addr32ORMA读写地址,字节寻址
inst_sram_wdata32ORAM写数据
inst_sram_rdata32IRAM读数据
与ID
id_to_if_allowin1Ipipe allowin
if_to_id_vld1Opipe valid
if_to_id_data64Opipe data(instruction 32-bits, pc 32-bits)
jump_bus33Ibranch instructions(enable 1bit,address 32-bits)

接口时序

ID.v

接口信号

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与IF
id_to_if_allowin1Opipe allowin
if_to_id_vld1Ipipe valid
if_to_id_data64Ipipe data(instruction 32-bits, pc 32-bits)
jump_bus33Obranch instructions(enable 1bit,address 32-bits)
与EXE
id_flush1I将id_data给清零
exe_front_flush1O将exe_data给清零
id_flush1I将id_data给清零
exe_to_id_allowin1Ipipe allowin
id_to_exe_vld1Opipe valid
id_to_exe_data169O{alu_op:21, shamt_is_shamt:1, imm_zero_ext_en:1, ins_R:1, ins_I:1, imm:16, mem_rd:1, mem_we:1, rf_we:1, rf_dst_addr:5, rt_data:32, rs_sfr_data_2:32, pc:32} 5:id_ctr_op:{ 4:ov_ins_pre 3:err_reverve 2:c0_has_int 1:break 0:syscall } , alu_op:22, shamt_is_shamt:1, imm_zero_ext_en:1, ins_R:1, ins_I:1, imm:16, lwx_bus_less2:8, swx_bus:9(增加了ins_sw), rf_we:4, rf_dst_addr:5, rt_data:32, rs_sfr_data_2:32, pc:32}
exe_bypass_bus38I{exe_rf_we:1, exe_rf_dst_addr:5, exe_rf_data:32}
exe_to_id_sfr_bus76I[75] exe_sfr_we1 [74:70] exe_sfr_w_addr1 [69:38] exe_sfr_data1 [37] exe_sfr_we2 [36:32] exe_sfr_w_addr2 [31:0] exe_sfr_data2
lwx_bus_less2 将其合并至id_to_exe_data中10Olwx类总线: ins_lb: 1, ins_lbu: 1, ins_lh: 1, ins_lhu: 1, ins_lwl: 1, ins_lwr: 1, ins_lw: 1, rs_low2: 2 mem_rd: 1
swx_bus 将其合并至id_to_exe_data中9Oswx类总线: ins_sw:1 ins_sb: 1, ins_sh: 1, ins_swl: 1, ins_swr: 1, mem_we[3:0]: 4
mul_div_busy1I正在进行乘法或除法运算
与MEM
mem_bypass_bus38I{mem_rf_we:1, mem_rf_dst_addr:5, mem_rf_data:32}
与WB
wb_to_rf_bus41I{rf_we:4, rf_addr:5, rf_data:32}
wb_exc_bus48I详见:3.4节 pc:32 c0_op:4 c0_int:6 c0_excode:5 exc:1

接口信号(RF.v)

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
与ID内部信号
rf_r_addr15IRF读地址1
rf_r_data132ORF读数据1
rf_r_addr25IRF读地址2
rf_r_data232ORF读数据2
rf_wen14IRF写使能1
rf_w_addr15IRF写地址1
rf_w_data132ORF写数据1

接口信号(SFR)

当写入同一地址时,以sfr_we_1优先

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与ID内部信号
sfr_r_addr15ISFR读地址1
sfr_r_data132OSFR读数据1
sfr_we_11ISFR写使能1
sfr_w_addr15ISFR写地址1
sfr_w_data132ISFR写数据1
sfr_we_21ISFR写使能2
sfr_w_addr25ISFR写地址2
sfr_w_data232ISFR写数据2

接口信号(SSR)

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与ID内部信号
c0_op4I3:保留着,先置为0 2:wb_bd:branch delay slot(本Lab8版本可以恒置为0) 1:wb_exc:由WB传回来的例外 0:syscall
c0_eret1Ieret
c0_int6I中断
c0_excode5I由WB传回来的excode
c0_wb_pc32I由WB传回来的PC值
c0_we1ISSR写使能(1:写,0:读)
c0_addr8ISSR写/读地址 [7:5]:c0_sel [5:0]:c0_id
c0_wdata32ISSR写数据
c0_rdata32OSSR读数据
c0_has_int1O发生中断

接口时序

电路设计

在这里插入图片描述

图3-4-1 译码电路分组(注:黄线少画了两条)

根据附录——MIPS指令。由于跳转指令不传递给EXE阶段,直接传递给IF阶段,且为纯组合逻辑输出,有可能成为关键路径,故对跳转指令单独处理。除了跳转指令外,涉及加法(减法归为加法)的指令如图3-4-1所示,即ins_addu、ins_addiu、ins_subu、ins_lw、ins_sw。

对于图3-4-1的拼接运算,可以当作移位运算执行。

EXE.v

接口信号

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与TOP(外接的DATA_RAM)
data_sram_en1O数据RAM使能信号,高电平有效
data_sram_wen4O数据RAM字节写使能信号,高电平有效(4个比特,应该代表32 = 4 bytes)
data_sram_addr32O数据RAM读写地址,字节寻址
data_sram_wdata32O数据RAM写数据
与ID
id_flush1O将id_data给清零
exe_front_flush1I将exe_data给清零
exe_to_id_allowin1Opipe allowin
id_to_exe_vld1Ipipe valid
id_to_exe_data169I{alu_op:21, shamt_is_shamt:1, imm_zero_ext_en:1, ins_R:1, ins_I:1, imm:16, mem_rd:1, mem_we:1, rf_we:1, rf_dst_addr:5, rt_data:32, rs_sfr_data_2:32, pc:32} 5:exe_ctr_op:{ 4:ov_ins_pre 3:err_reverve 2:c0_has_int 1:break 0:syscall } , alu_op:22, shamt_is_shamt:1, imm_zero_ext_en:1, ins_R:1, ins_I:1, imm:16, lwx_bus_less2:8, swx_bus:9(增加了ins_sw), rf_we:4, rf_dst_addr:5, rt_data:32, rs_sfr_data_2:32, pc:32}
exe_bypass_bus41O{exe_rf_we:4, exe_rf_dst_addr:5, exe_rf_data:32}
exe_to_id_sfr_bus76O[75] exe_sfr_we1 [74:70] exe_sfr_w_addr1 [69:38] exe_sfr_data1 [37] exe_sfr_we2 [36:32] exe_sfr_w_addr2 [31:0] exe_sfr_data2
mul_div_busy1O正在进行乘法或除法运算
lwx_bus 将其合并至id_to_exe_data中10Ilwx类总线: ins_lb: 1, ins_lbu: 1, ins_lh: 1, ins_lhu: 1, ins_lwl: 1, ins_lwr: 1, ins_lw: 1, rs_low2: 2 mem_rd: 1
swx_bus 将其合并至id_to_exe_data中9Iswx类总线: ins_sw:1, ins_sb: 1, ins_sh: 1, ins_swl: 1, ins_swr: 1, mem_we[3:0]: 4
与MEM
mem_front_flush1O将mem_data给清零
exe_flush1I将exe_data给清零
id_flush1O将id_data给清零
mem_to_id_allowin1Ipipe allowin
exe_to_mem_vld1Opipe valid
exe_to_mem_data99O{mem_rd:1, rf_we:1, rf_dst_addr:5, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc), exe_result:32} {exe_exc_bus:16, lwx_bus: 10, rf_we:4, rf_dst_addr:5, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc), exe_result:32}
lwx_bus 将其合并至id_to_exe_data中10Olwx类总线: ins_lb: 1, ins_lbu: 1, ins_lh: 1, ins_lhu: 1, ins_lwl: 1, ins_lwr: 1, ins_lw: 1, rs_low2: 2 mem_rd: 1
exe_exc_bus (归于exe_to_mem_data)16O详见:3.4节 c0_op:4 c0_int:6 c0_excode:5 exc:1

接口信号(ALU.v)

暂时不需要时钟和复位,纯组合逻辑

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与ID内部信号
alu_shamt6IALU移位(R-指令的shamt部分)
alu_op19IALU操作(加、减、乘除、位运算)
alu_add_ov1O加法/减法溢出
alu_din132IALU输入1
alu_din232IALU输入2
alu_out32OALU输出
mul_div_busy1O正在进行乘法或除法运算

接口信号(MUL_DIV.v)

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与ALU内部信号
alu_mult1I有符号乘
alu_multu1I无符号乘
alu_div1I有符号除
alu_divu1I无符号除
alu_mthi1I将寄存器 rs 的值写入到 HI 寄存器中
alu_mtlo1I将寄存器 rs 的值写入到LO寄存器中
alu_din132IALU输入1
alu_din232IALU输入2
exe_to_id_sfr_bus76O[75] exe_sfr_we1 [74:70] exe_sfr_w_addr1 [69:38] exe_sfr_data1 [37] exe_sfr_we2 [36:32] exe_sfr_w_addr2 [31:0] exe_sfr_data2
mul_div_busy1O正在进行乘法或除法运算

接口信号MUL.v

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与ALU内部信号
mul_din_vld1I数据有效信号
mul_din133I乘数1
mul_din233I乘数2
mul_result_hi32O乘法高32位
mul_result_lo32O乘法低32位

接口信号DIVU.v

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与ALU内部信号
divu_din_vld1I数据有效信号
divu_din133I被除数
divu_din233I除数
divu_hi32O结果高32位
divu_lo32O结果低32位

接口信号DIVS.v

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与ALU内部信号
divs_din_vld1I数据有效信号
divs_din133I被除数
divs_din233I除数
divs_hi32O结果高32位
divs_lo32O结果低32位

接口时序

MEM.v

接口信号

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与TOP(外接的DATA_RAM)
data_sram_rdata32I数据RAM读数据
与EXE
mem_front_flush1I将mem_data给清零
exe_flush1O将exe_data给清零
mem_to_exe_allowin1Opipe allowin
exe_to_mem_vld1Ipipe valid
exe_to_mem_data99I{mem_rd:1, rf_we:1, rf_dst_addr:5, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc), exe_result:32} {exe_exc_bus:16, lwx_bus: 10, rf_we:4, rf_dst_addr:5, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc), exe_result:32}
lwx_bus 将其合并至id_to_exe_data中10Ilwx类总线: ins_lb: 1, ins_lbu: 1, ins_lh: 1, ins_lhu: 1, ins_lwl: 1, ins_lwr: 1, ins_lw: 1, rs_low2: 2 mem_rd: 1
exe_exc_bus (归为exe_to_mem_data)16I详见:3.4节 c0_op:4 c0_int:6 c0_excode:5 exc:1
与WB
mem_flush1I将mem_data给清零
wb_front_flush1O将wb_data给清零
wb_to_mem_allowin1Ipipe allowin
mem_to_wb_vld1Opipe valid
mem_to_wb_data89O{mem_exc_bus:16, rf_we:4, rf_dst_addr:5, mem_result:32, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc)}
mem_exc_bus (归为mem_to_wb_data)16O详见:3.4节 c0_op:4 c0_int:6 c0_excode:5 exc:1
与ID
mem_bypass_bus38O{mem_rf_we:4, mem_rf_dst_addr:5, mem_rf_data:32}
wb_exc_bus16O详见:3.4节 c0_op:4 c0_int:6 c0_excode:5 exc:1

WB.v

接口信号

名称宽度方向描述
时钟与复位
clk1I时钟信号,来自clk_pll的输出时钟
resetn1I复位信号,低电平同步复位
与TOP
debug_wb_pc32O写回级(多周期最后一级)的PC,需要myCPU里将PC一路传递到写回级(与原书保持一致)
debug_wb_rf_wen4O写回级写寄存器堆(regfiles)的写使能,为字节使能,如果myCPU写regfiles为单字节写使能,则将写使能扩展成4位即可(与原书保持一致)
debug_wb_rf_wnum5O写回级写regfiles的目的寄存器号(与原书保持一致)
debug_wb_rf_wdata32O写回级写regfiles的写数据(与原书保持一致)
与MEM
mem_flush1O将mem_data给清零
wb_front_flush1I将wb_data给清零
wb_to_mem_allowin1Opipe allowin
mem_to_wb_vld1Ipipe valid
mem_to_wb_data89I{ mem_exc_bus:16, rf_we:4, rf_dst_addr:5, mem_result:32, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc)}
mem_exc_bus (归于mem_to_wb_data)16I详见:3.4节 c0_op:4 c0_int:6 c0_excode:5 exc:1
与ID
wb_to_rf_bus41O{rf_we:4, rf_addr:5, rf_data:32}
wb_exc_bus48O详见:3.4节 pc:32 c0_op:4 c0_int:6 c0_excode:5 exc:1

接口时序

附录——参考

  1. 参考:处理机流水线------经典五段流水线-优快云博客

附录——原书指令

指令sel_nextpcinst_ram_weninst_ram_wensel_alu_src1sel_alu_src2alu_opdata_ram_endata_ram_wenrf_wesel_rf_dstsel_rf_res
ADDU0001100010010000000000010010010
ADDIU0001100010100000000000010010100
SUBU0001100010010000000000100010010
LW0001100010100000000000011010101
SW0001100010100000000000011100000
BEQ0010100000000000000000000000000
BNE0010100000000000000000000000000
JAL0100100101000000000000010011000
JR1000100000000000000000000000000
SLT0001100010010000000001000010010
SLTU0001100010010000000010000010010
SLL0001101000010001000000000010010
SRL0001101000010010000000000010010
SRA0001101000010100000000000010010
LUI0001100000101000000000000010100
AND0001100010010000000100000010010
OR0001100010010000010000000010010
XOR0001100010010000100000000010010
NOR0001100010010000001000000010010

LAB9——后记

前述

发现有些寄存器是Lab9的,但是已经在Lab8写过了,那就算Lab8的吧,不再修改了。

中断优先级

Lab8只有syscall这一个例外,因此不需要考虑中断的优先级,但是Lab9增加许多例外,因此是需要考虑中断的优先级的,即:当一条指令同时触发多个例外时的优先级:

在这里插入图片描述

ExcCode编码

在这里插入图片描述

BadVAddr

原书解释:“BadVAddr寄存器整体只有一个域,其更新来源只有一个,即报地址错例外的时候将导致出错的虚地址写入该寄存器。这里要注意以下几点:首先记录的是虚地址;其次如果是地址错例外,出错的虚地址就是PC;最后,如果导致地址出错的原因是地址非对齐,那BadVAddr的低两位要严格地更新为非对齐地址的低两位。不要为了省几个触发器而把各级流水级缓存中保存的PC的最低两位强行转为0。”

需要注意的是BadVAddr寄存器是对软件是只读不可写的。

在这里插入图片描述

本人不理解原书第7章的P179页对BadVAddr的Verilog代码的描述,为什么只有ADEL,而没有ADES,大家都是地址错误啊,此处存疑。

  1. BadVAddr涉及的指令有:lw/lb/lbu/lh/lhu/sw/sb/sh
指令
ADELADES
lwsw4的整数倍
lhsh2的整数倍
lhu
  1. 经本人遍历load/store想着指令,得出以下结论:BadVAddr不涉及:lb/lbu/sb/lwr/lwl/swr/swl

count 与 compare

比较简单,按书上的来。

中断

  1. 原本我对中断处理毫无头绪,后发现原书P169有言:“has_int = ((Cause.IP[7:0] & Status.IM[7:0]) != 8’h00) && Status.IE1’b1 && Status.EXL1’b0;”于是本人直接抄此代码

    1. 原书:“简单解释一下,就是外部的中断通过处理器核的引脚设置Cause寄存器中对应的中断状态位,当这个中断状态位自身对应的使能位有效且全局使能位也有效,那么CPU内部就认为接收到中断。显然,这里CPU并不在意到底接收到的是一个外部中断还是多个外部中断。当确实同时接收到多个中断时,后续的处理交给软件上的中断处理函数进行。”

      1. 有人has_int之后,之前将has_int引到ID阶段,把has_int当作指令处理,即类似syscall指令进行处理,这样就清晰多了。

        1. 硬件中断是软件只读不可写的,那怎么处理Cause寄存器中的6个bits的硬件中断呢?观察顶层:

          在这里插入图片描述

          好像可以和btn或switch进行相连,本人不确定如何处理,暂时将其置为全零:

          在这里插入图片描述

整数溢出

指令
ADD有例外ADDIU无例外
ADDI
SUBSUBU无例外

保留指令例外

  1. 原书:“当执行一条未实现的指令时,触发保留指令例外”

    1. 本人直接这样处理了:

      在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Greate AUK

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

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

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

打赏作者

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

抵扣说明:

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

余额充值