电脑里的CPU 起什么作用

电脑里的CPU 起什么作用,第1张

一、 指令系统

要讲CPU,就必须先讲一下指令系统。指令系统指的是一个CPU所能够处理的全部指

令的集合,是一个CPU的根本属性。比如我们现在所用的CPU都是采用x86指令集的,他们都是同一类型的CPU,不管是PIII、Athlon或Joshua。我们也知道,世界上还有比PIII和Athlon快得多的CPU,比如Alpha,但它们不是用x86指令集,不能使用数量庞大的基于x86指令集的程序,如Windows98。之所以说指令系统是一个CPU的根本属性,是因为指令系统决定了一个CPU能够运行什么样的程序。

所有采用高级语言编出的程序,都需要翻译(编译或解释)成为机器语言后才能运行,这些机器语言中所包含的就是一条条的指令。

1、 指令的格式

一条指令一般包括两个部分:操作码和地址码。操作码其实就是指令序列号,用来告诉CPU需要执行的是那一条指令。地址码则复杂一些,主要包括源操作数地址、目的地址和下一条指令的地址。在某些指令中,地址码可以部分或全部省略,比如一条空指令就只有操作码而没有地址码。

举个例子吧,某个指令系统的指令长度为32位,操作码长度为8位,地址长度也为8位,且第一条指令是加,第二条指令是减。当它收到一个“00000010000001000000000100000110”的指令时,先取出它的前8位操作码,即00000010,分析得出这是一个减法操作,有3个地址,分别是两个源操作数地址和一个目的地址。于是,CPU就到内存地址00000100处取出被减数,到00000001处取出减数,送到ALU中进行减法运算,然后把结果送到00000110处。

这只是一个相当简单化的例子,实际情况要复杂的多。

2、 指令的分类与寻址方式

一般说来,现在的指令系统有以下几种类型的指令:

(1)算术逻辑运算指令

算术逻辑运算指令包括加减乘除等算术运算指令,以及与或非异或等逻辑运算指令。现在的指令系统还加入了一些十进制运算指令以及字符串运算指令等。

(2)浮点运算指令

用于对浮点数进行运算。浮点运算要大大复杂于整数运算,所以CPU中一般还会有专门负责浮点运算的浮点运算单元。现在的浮点指令中一般还加入了向量指令,用于直接对矩阵进行运算,对于现在的多媒体和3D处理很有用。

(3)位操作指令

学过C的人应该都知道C语言中有一组位操作语句,相对应的,指令系统中也有一组位操作指令,如左移一位右移一位等。对于计算机内部以二进制不码表示的数据来说,这种操作是非常简单快捷的。

(4)其他指令

上面三种都是运算型指令,除此之外还有许多非运算的其他指令。这些指令包括:数据传送指令、堆栈操作指令、转移类指令、输入输出指令和一些比较特殊的指令,如特权指令、多处理器控制指令和等待、停机、空操作等指令。

对于指令中的地址码,也会有许多不同的寻址(编址)方式,主要有直接寻址,间接寻址,寄存器寻址,基址寻址,变址寻址等,某些复杂的指令系统会有几十种甚至更多的寻址方式。

3、 CISC与RISC

CISC,Complex Instruction Set Computer,复杂指令系统计算机。RISC,Reduced Instruction Set Computer,精简指令系统计算机。虽然这两个名词是针对计算机的,但下文我们仍然只对指令集进行研究。

(1)CISC的产生、发展和现状

一开始,计算机的指令系统只有很少一些基本指令,而其他的复杂指令全靠软件编译时通过简单指令的组合来实现。举个最简单的例子,一个a乘以b的操作就可以转换为a个b相加来做,这样就用不着乘法指令了。当然,最早的指令系统就已经有乘法指令了,这是为什么呢?因为用硬件实现乘法比加法组合来得快得多。

由于那时的计算机部件相当昂贵,而且速度很慢,为了提高速度,越来越多的复杂指令被加入了指令系统中。但是,很快又有一个问题:一个指令系统的指令数是受指令操作码的位数所限制的,如果操作码为8位,那么指令数最多为256条(2的8次方)。

那么怎么办呢?指令的宽度是很难增加的,聪明的设计师们又想出了一种方案:操作码扩展。前面说过,操作码的后面跟的是地址码,而有些指令是用不着地址码或只用少量的地址码的。那么,就可以把操作码扩展到这些位置。

举个简单的例子,如果一个指令系统的操作码为2位,那么可以有00、01、10、11四条不同的指令。现在把11作为保留,把操作码扩展到4位,那么就可以有00、01、10、1100、1101、1110、1111七条指令。其中1100、1101、1110、1111这四条指令的地址码必须少两位。

然后,为了达到操作码扩展的先决条件:减少地址码,设计师们又动足了脑筋,发明了各种各样的寻址方式,如基址寻址、相对寻址等,用以最大限度的压缩地址码长度,为操作码留出空间。

就这样,慢慢地,CISC指令系统就形成了,大量的复杂指令、可变的指令长度、多种的寻址方式是CISC的特点,也是CISC的缺点:因为这些都大大增加了解码的难度,而在现在的高速硬件发展下,复杂指令所带来的速度提升早已不及在解码上浪费点的时间。除了个人PC市场还在用x86指令集外,服务器以及更大的系统都早已不用CISC了。x86仍然存在的唯一理由就是为了兼容大量的x86平台上的软件。

(2)RISC的产生、发展和现状

1975年,IBM的设计师John Cocke研究了当时的IBM370CISC系统,发现其中占总指令数仅20%的简单指令却在程序调用中占了80%,而占指令数80%的复杂指令却只有20%的机会用到。由此,他提出了RISC的概念。

事实证明,RISC是成功的。80年代末,各公司的RISC CPU如雨后春笋般大量出现,占据了大量的市场。到了90年代,x86的CPU如pentium和k5也开始使用先进的RISC核心。

RISC的最大特点是指令长度固定,指令格式种类少,寻址方式种类少,大多数是简单指令且都能在一个时钟周期内完成,易于设计超标量与流水线,寄存器数量多,大量操作在寄存器之间进行。由于下文所讲的CPU核心大部分是讲RISC核心,所以这里就不多介绍了,对于RISC核心的设计下面会详细谈到。

RISC目前正如日中天,Intel的Itanium也将最终抛弃x86而转向RISC结构。

二、CPU内核结构

好吧,下面来看看CPU。CPU内核主要分为两部分:运算器和控制器。

(一) 运算器

1、 算术逻辑运算单元ALU(Arithmetic and Logic Unit)

ALU主要完成对二进制数据的定点算术运算(加减乘除)、逻辑运算(与或非异或)以及移位操作。在某些CPU中还有专门用于处理移位操作的移位器。

通常ALU由两个输入端和一个输出端。整数单元有时也称为IEU(Integer Execution Unit)。我们通常所说的“CPU是XX位的”就是指ALU所能处理的数据的位数。

2、 浮点运算单元FPU(Floating Point Unit)

FPU主要负责浮点运算和高精度整数运算。有些FPU还具有向量运算的功能,另外一些则有专门的向量处理单元。

3、通用寄存器组

通用寄存器组是一组最快的存储器,用来保存参加运算的操作数和中间结果。

在通用寄存器的设计上,RISC与CISC有着很大的不同。CISC的寄存器通常很少,主要是受了当时硬件成本所限。比如x86指令集只有8个通用寄存器。所以,CISC的CPU执行是大多数时间是在访问存储器中的数据,而不是寄存器中的。这就拖慢了整个系统的速度。而RISC系统往往具有非常多的通用寄存器,并采用了重叠寄存器窗口和寄存器堆等技术使寄存器资源得到充分的利用。

对于x86指令集只支持8个通用寄存器的缺点,Intel和AMD的最新CPU都采用了一种叫做“寄存器重命名”的技术,这种技术使x86CPU的寄存器可以突破8个的限制,达到32个甚至更多。不过,相对于RISC来说,这种技术的寄存器操作要多出一个时钟周期,用来对寄存器进行重命名。

4、 专用寄存器

专用寄存器通常是一些状态寄存器,不能通过程序改变,由CPU自己控制,表明某种状态。

(二) 控制器

运算器只能完成运算,而控制器用于控制着整个CPU的工作。

1、 指令控制器

指令控制器是控制器中相当重要的部分,它要完成取指令、分析指令等操作,然后交给执行单元(ALU或FPU)来执行,同时还要形成下一条指令的地址。

2、 时序控制器

时序控制器的作用是为每条指令按时间顺序提供控制信号。时序控制器包括时钟发生器和倍频定义单元,其中时钟发生器由石英晶体振荡器发出非常稳定的脉冲信号,就是CPU的主频;而倍频定义单元则定义了CPU主频是存储器频率(总线频率)的几倍。

3、 总线控制器

总线控制器主要用于控制CPU的内外部总线,包括地址总线、数据总线、控制总线等等。

4、中断控制器

中断控制器用于控制各种各样的中断请求,并根据优先级的高低对中断请求进行排队,逐个交给CPU处理。

(三) CPU核心的设计

CPU的性能是由什么决定的呢?单纯的一个ALU速度在一个CPU中并不起决定性作用,因为ALU的速度都差不多。而一个CPU的性能表现的决定性因素就在于CPU内核的设计。

1、超标量(Superscalar)

既然无法大幅提高ALU的速度,有什么替代的方法呢?并行处理的方法又一次产生了强大的作用。所谓的超标量CPU,就是只集成了多个ALU、多个FPU、多个译码器和多条流水线的CPU,以并行处理的方式来提高性能。

超标量技术应该是很容易理解的,不过有一点需要注意,就是不要去管“超标量”之前的那个数字,比如“9路超标量”,不同的厂商对于这个数字有着不同的定义,更多的这只是一种商业上的宣传手段。

2、流水线(Pipeline)

流水线是现代RISC核心的一个重要设计,它极大地提高了性能。

对于一条具体的指令执行过程,通常可以分为五个部分:取指令,指令译码,取操作数,运算(ALU),写结果。其中前三步一般由指令控制器完成,后两步则由运算器完成。按照传统的方式,所有指令顺序执行,那么先是指令控制器工作,完成第一条指令的前三步,然后运算器工作,完成后两步,在指令控制器工作,完成第二条指令的前三步,在是运算器,完成第二条指令的后两部……很明显,当指令控制器工作是运算器基本上在休息,而当运算器在工作时指令控制器却在休息,造成了相当大的资源浪费。解决方法很容易想到,当指令控制器完成了第一条指令的前三步后,直接开始第二条指令的操作,运算单元也是。这样就形成了流水线系统,这是一条2级流水线。

如果是一个超标量系统,假设有三个指令控制单元和两个运算单元,那么就可以在完成了第一条指令的取址工作后直接开始第二条指令的取址,这时第一条指令在进行译码,然后第三条指令取址,第二条指令译码,第一条指令取操作数……这样就是一个5级流水线。很显然,5级流水线的平均理论速度是不用流水线的4倍。

流水线系统最大限度地利用了CPU资源,使每个部件在每个时钟周期都工作,大大提高了效率。但是,流水线有两个非常大的问题:相关和转移。

在一个流水线系统中,如果第二条指令需要用到第一条指令的结果,这种情况叫做相关。以上面哪个5级流水线为例,当第二条指令需要取操作数时,第一条指令的运算还没有完成,如果这时第二条指令就去取操作数,就会得到错误的结果。所以,这时整条流水线不得不停顿下来,等待第一条指令的完成。这是很讨厌的问题,特别是对于比较长的流水线,比如20级,这种停顿通常要损失十几个时钟周期。目前解决这个问题的方法是乱序执行。乱序执行的原理是在两条相关指令中插入不相关的指令,使整条流水线顺畅。比如上面的例子中,开始执行第一条指令后直接开始执行第三条指令(假设第三条指令不相关),然后才开始执行第二条指令,这样当第二条指令需要取操作数时第一条指令刚好完成,而且第三条指令也快要完成了,整条流水线不会停顿。当然,流水线的阻塞现象还是不能完全避免的,尤其是当相关指令非常多的时候。

另一个大问题是条件转移。在上面的例子中,如果第一条指令是一个条件转移指令,那么系统就会不清楚下面应该执行那一条指令?这时就必须等第一条指令的判断结果出来才能执行第二条指令。条件转移所造成的流水线停顿甚至比相关还要严重的多。所以,现在采用分支预测技术来处理转移问题。虽然我们的程序中充满着分支,而且哪一条分支都是有可能的,但大多数情况下总是选择某一分支。比如一个循环的末尾是一个分支,除了最后一次我们需要跳出循环外,其他的时候我们总是选择继续循环这条分支。根据这些原理,分支预测技术可以在没有得到结果之前预测下一条指令是什么,并执行它。现在的分支预测技术能够达到90%以上的正确率,但是,一旦预测错误,CPU仍然不得不清理整条流水线并回到分支点。这将损失大量的时钟周期。所以,进一步提高分支预测的准确率也是正在研究的一个课题。

越是长的流水线,相关和转移两大问题也越严重,所以,流水线并不是越长越好,超标量也不是越多越好,找到一个速度与效率的平衡点才是最重要的。

三、CPU的外核

1、解码器(Decode Unit)

这是x86CPU才有的东西,它的作用是把长度不定的x86指令转换为长度固定的类似于RISC的指令,并交给RISC内核。解码分为硬件解码和微解码,对于简单的x86指令只要硬件解码即可,速度较快,而遇到复杂的x86指令则需要进行微解码,并把它分成若干条简单指令,速度较慢且很复杂。好在这些复杂指令很少会用到。

Athlon也好,PIII也好,老式的CISC的x86指令集严重制约了他们的性能表现。

2、一级缓存和二级缓存(Cache)

以及缓存和二级缓存是为了缓解较快的CPU与较慢的存储器之间的矛盾而产生的,以及缓存通常集成在CPU内核,而二级缓存则是以OnDie或OnBoard的方式以较快于存储器的速度运行。对于一些大数据交换量的工作,CPU的Cache显得尤为重要。

好了,看到了吧,CPU其实也就这样,并不是很神秘。

1.什么是寄存器 所谓寄存器(register),它是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。其实寄存器就是一种常用的时序逻辑电路,但这种时序逻辑电路只包含存储电路。寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器能存储1位二进制数,所以由N个锁存器或触发器可以构成N位寄存器。2.寄存器与CPU指令 在讲CPU的寄存器之前,我们先了解一下CPU指令系统。指令系统指的是一个CPU所能够处理的全部指令的集合,Athlon XP和P4都是基于x86指令集,这是CPU的根本属性,决定CPU运行什么样的程序。 指令一般分为:算术逻辑运算指令、浮点运算指令、位操作指令及其他的一些非运算指令,其中整数、地址、指令指针和浮点数据是按照数据形式来划分的。通常我们把需要CPU进行不同处理的单个数据称为标量数据(Scala Data)。标量数据既可以是整数数据,也可以是浮点数据。其中整数标量数据的存放区一般为通用寄存器(GPR),浮点标量数据的存放区一般为浮点寄存器(FPR)。与标量数据相对的是矢量数据(Vector Data),所谓矢量数据就是指一列需要由处理器作相同处理的数据集合。比如处理器在做MP3编码的过程中,需要对内存中的音频文件里的各字节数据作相同的MP3编码操作。那么通常使用MMX或SSE这类单指令多数据流(SIMD)指令,将数个字节打包为一组矢量数据,存放在MMX或SSE寄存器中,再送往相应的功能单元进行统一操作。 其中通用寄存器是处理器中最快的存储器,用来保存参加运算的操作数和中间结果。在通用寄存器的设计上,RISC与CISC(也就是我们常说的x86架构)有着很大的不同。CISC的寄存器通常很少——只有8个通用寄存器。由于CPU在执行指令过程中,存在指令依赖性,在一定程度上使得x86 CPU不能在每个时钟周期中立即发布大量的指令。所谓“依赖性”就是指令的执行需要前个指令的运算结果。比如程序员经常使用的分支程序,请看下面这个例子: A=C*1 B=A+2 只要变量A的值还不知道,B=A+2就不能进行运算。也就是说,只要指令1的结果没有写进寄存器,CPU调度器就不能把指令2发布到执行单元。由于程序分支会造成具有较长流水线CPU运行停滞的,目前常用的解决方法是采用分支预测。 不过,分支预测同样存在一个问题:流水线越长,指令潜伏期也越长,等待前一指令运算结果的时间也越长,同样会造成CPU运行停滞。我们知道,程序指令通常都有各类型的条件分支语句,通过验证条件决定执行路线。但CPU执行单元内是通过一项特殊的预测机制选择一条路线直接执行(这样可以避免验证语句条件而处于等待情况),然后在后面进行验证。如果预测正确则继续往下执行,如果发现以前的预测错误,那么就必须返回原地重新开始,以前的指令就会作废。 因此,管线越长,意味着出现分支预测错误的机会就越多,越多在管线内的指令会被清除掉,而且重新让管道填满指令的时间也会越长。对于普通处理器来说,如果出现分支预测错误,CPU就不得不将整条流水线清空后从错误的地方重新装满数据、重新执行。毫无疑问这将花更多的时间,整体性能就会下降。因此,针对通用寄存器少的问题,在x86架构中比较完美的解决方法就是增加寄存器的数量和采用“乱序执行”。3.为什么寄存器不够用 在上面我们已经提到,寄存器只是用来暂时存放指令值的,如果CPU需要把两个值加起来,它需要用1个寄存器来存放运算结果,用2个寄存器来存放相加的数值。例如,在以下的方程式中:A = 2 + 4 * 在寄存器1储存“2”; * 在寄存器2储存“4”; * 在寄存器3储存“寄存器1 + 寄存器 2”; 因为在微处理器里面有超过3个寄存器,因此这个运算能够轻易地执行,不会造成用光寄存器的情况。在这些运算被执行之后,所有的3个数值都能够被保留并重新使用,因此如果我们再想在结果加上2的话,处理器只需要执行:寄存器 1 + 寄存器 3 就可以了。如果微处理器仅有2个剩余的寄存器,而我们又需要再次使用2和4的值,那么这些值在覆盖结果A之前,必须储存在主内存之中 。运算执行的过程则会变成如下所示: * 在寄存器1储存 “2”; * 在寄存器2储存“4”; * 在主内存的某个空间储存“寄存器1 + 寄存器2”; 我们可以看到这里使用了其它的内存访问过程,而在这期间其实还有我们没有提到的其它处理过程,比如主内存的定位也需要占据寄存器,以便让CPU 告诉装载/储存单元该往哪里发送数据 。如果我们需要使用到这些结果的话,那么CPU将不得不首先到主内存中找回这些结果,把目前满载的寄存器驱逐一些数据,把它们写入主内存,然后再把寻找到的数据储存在寄存器里。 这里大家应该能够明白吧,对内存的访问次数将会可怕地增加;你需要访问内存的时间越多,那么处理器等待工作完成的时间就越长——因而造成性能的下降。因此面对超标量CPU在并行处理大量运算,x86体系仅有的8个通用寄存器远远不能满足需要,在同一时钟周期中,如果有3个指令发布,你就需要3个输出寄存器和6个输入寄存器。我们该怎么办呢?聪明的工程师们发现了突破这个限制的方法:“寄存器重命名”。 4.寄存器重命名技术 寄存器重命名,是CPU在解码过程中对寄存器进行重命名,解码器把“其它”的寄存器名字变为“通用”的寄存器名字,本质上是通过一个表格把x86寄存器重新映射到其它寄存器,这样可以让实际使用到的寄存器远大于8个。这样做的好处除了便于前面指令发生意外或分支预测出错时取消外,还避免了由于两条指令写同一个寄存器时的等待。 下面我们以一个超标量CPU执行8个算术指令为例:假设它在每个时钟周期中能对2个指令解码,引出计算结果是在指令发布后3个时钟周期发生的: (1)在第1个时钟周期,两个指令发布:它们互不关联,因此,它们将在3个时钟周期后(第4个时钟周期)引出; (2)在第2个时钟周期,我们首次遇到了“指令依赖”,指令3需要指令2的结果,此时指令3不能开始发布; (3)如果是按序执行,指令4、5、6就不能在指令3前发布。只有在第5个时钟周期时(指令2的结果已得到)才能发布指令3; (4)在第6个时钟周期有个大问题:我们想把结果写到寄存器R1,但这将改变指令5的结果。因此,我们只有在R1空闲时(第10个时钟周期)才能发布指令6。 按照正常情况处理的话,尽管这个CPU每个时钟周期可以对2个指令解码,但它每个时钟周期的指令执行数只有0.53。如果每次程序所需的寄存器正被使用,我们可以把数据放到其它的寄存器中,在第6个时钟周期将寄存器R1重命名,指令6和指令8不再耽误CPU的工作。结果是我们能够将每个时钟周期的指令执行数提高50%。寄存器重命名技术可以使x86 CPU的寄存器可以突破8个的限制,达到32个甚至更多。寄存器重命名技术现在已经深深地扎根于超标量CPU中了。5.乱序执行技术 除此之外,处理器工程师还引入了乱序执行技术,从一定程度上来缓解通用寄存器不足的问题。采用乱序执行技术的目的是为了使CPU内部电路满负荷运转并相应提高了CPU运行程序的速度。 这好比请A、B、C三个名人为春节联欢晚会题写横幅“春节联欢晚会”六个大字,每人各写两个字,如果这时在一张大纸上按顺序由A写好“春节”后再交给B写“联欢”,然后再由C写“晚会”,那么这样在A写的时候,B和C必须等待,而在B写的时候C仍然要等待而A已经没事了。但如果采用三个人分别用三张纸同时写的做法,那么B和C都不必等待就可以同时各写各的了,甚至C和B还可以比A先写好也没关系(就像乱序执行),但当他们都写完后就必须重新在横幅上按“春节联欢晚会”的顺序排好(自然可以由别人做,就象CPU中乱序执行后的重新排列单元)才能挂出去。 不过,虽然采用寄存器重命名技术、乱序执行技术,但仍不能从根本上解决x86处理器通用寄存器不足的问题。以寄存器重命名技术来说,这种技术的寄存器操作相对于RISC来说,要花费一个时钟周期来对寄存器进行重命名,这无形中降低了处理器性能以及流水线工作效率,也增加了程序和编译器的优化难度。针对这个问题,最新的x86-64架构中(K8处理器),AMD在x86架构基础上将通用寄存器和SIMD寄存器的数量增加了1倍:其中新增了8个通用寄存器以及8个SIMD寄存器作为原有x86处理器寄存器的扩充。 这些通用寄存器都工作在64位模式下,经过64位编码的程序就可以使用到它们。这些64位寄存器称为RAX、RBX、RCX、RDX、RDI、RSI、RBP、RSP、RIP以及EFLAGS,在32位环境下并不完全使用到这些寄存器,同时AMD也将原有的EAX等寄存器扩展至64位的RAX,这样可以增强通用寄存器对字节的操作能力。从扩充方式上看,EAX等寄存器可以看做是RAX的一个子集,系统仍然可以完整地执行以往的32位编码程序。增加通用寄存器除了可高效存储数据外,还可作为寻址时的地址指针,从而缩短指令长度和指令执行时间,加快CPU的运算处理速度,同时也给编程带来方便。 此外,为了保证K8的分支预测更有效率,K8的分支预测寄存器增加到64个。分支指令可以被设为真或假,而每个指令中的6位被分配到单独一个预测寄存器中,只有预测寄存器被设定为“真”时,那些指向预测寄存器为“真”的指令结果才会被执行。其次由于所有的分支都能并行执行,CPU所花的时间同只执行单个分支的时间是相同的,降低了预测出错的风险。第三由于CPU不再跳跃执行,它不会把程序代码分成小块。也就是说,稍前和稍后的程序代码可以打包。这样CPU能够一并将它们发布,增大并行工作量。从而使性能提高10%~15%,特别是在整数代码部分。 不过在x86-64中,寄存器的扩展部分似乎仅对于整数、地址数据有效。对浮点和向量数据则仍然保持原样。我们能从K8向64位的扩展所获得的好处,只不过是可以在同样一条指令中,处理更大数值的整数数值以及管理空间更大的内存区域而已。而在32位的情况下,由于通用寄存器只能容纳最大32位的数据,因此显然要花费更多条指令对尺寸超过32位的数据进行处理。这种改进对服务器、科学计算这样的领域具有一定的意义,但显然并不是普通家用环境急需的改进。可以说,处理器的寄存器对处理器的性能有着巨大的影响。但是无论怎么发展,通用型CPU目前还没有脱离x86架构的限制,也许有一天,新的寄存器技术能让我们的CPU变得更加功能强大!


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/465066.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-06-04
下一篇2023-06-04

发表评论

登录后才能评论

评论列表(0条)

    保存