
FPGA
文章平均质量分 74
小灰灰的FPGA
从事FPGA开发设计,图像处理爱好者,芯片驱动控制爱好者,数据处理算法爱好者,通信行业工作者
展开
-
xilinx的vivado工具综合一直转圈圈,卡死后如何解决?
vivado业界内好用的EDA工具,也会出现各种各样的bug,莫名其妙,验证影响开发工作。在综合过程中,出现综合一直转圈圈,时间过去很久竟然还在synth综合。也就是图中的bug。从11点31开始synth,结果发现过去4分钟,还是一直转圈圈,此时卡死后,需要采用一定的方法进行解决。很多人尝试关闭工程,重新打开,仍然是这个bug,甚至有的人重新建工程,重装vivado软件,耗时又耗费精力。个人看法是在PC的缓存重新开辟内存,跑vivado的综合布线策略,其实就是完全摆脱以前的综合布线生成bit的路径。原创 2024-12-20 09:00:00 · 4102 阅读 · 0 评论 -
基于FDMA和AXI4接口的DDR4遍历读写测试
对于DDR的内存地址读写,有两种思路,一种是基于软核的读写测试,通过串口打印测试报告来查看,这种方式是基于C语言的DDR的地址写入与读取,并显示对应的测试结果;以下是简单的测试框架,ddr4_rw_fdma是预留的fdma的读写数据接口,用于DDR4遍历读写测试。FDMA,可以理解为帧格式的DMA操作,一种简易的DMA的操作方式,将AXIfull接口数据转换成读写测试数据接口,开放给用户侧使用,开发者使用相对方便,对于逻辑处理也更简单,不需要关注AXIfull的内部通道,比如:读通道,写通道,写响应等。原创 2024-12-19 01:00:00 · 1010 阅读 · 1 评论 -
vivado时序优化——约束异步时钟组set_clock_groups
异步时钟组,英文名称为Asynchronous Clock Groups,在vivado xdc约束命令为 set_clock_groups。需要注意的是,相比于常规时序约束, set_clock_groups约束命令具有更高的优先级。如果需要约束和报告异步时钟之间的某些路径,则必须只使用常规时钟约束,而不是设置_clock_组。从字面上理解,两个时钟为异步时钟,不需要分析这两个时钟之间的所有路径,在分析过程中,忽略所有的时序路径。原创 2024-12-18 06:00:00 · 2657 阅读 · 0 评论 -
UltraScale+FPGA中GTY的TX路径时钟详解——以40G的ETH MAC IP为例
经过原语IBUFDS_GTE4生成gt_refclk,进入GTYE4_COMMON和GTYE4_CHANNEL,通过QPLLREFCLKSEL[2:0]参数进行时钟输入的选择,将GTREFCLK00输入至QPLL0中,GTREFCLK00对应ge_refclk。TX_PROGCLK_SEL设置为PREPT,也就是对应的数字为01,时钟路径分为两路,总时钟图中蓝线分叉部分,一路给到TX PMA的Phase Interp,用于生成TXOUTCLKPCS;在pg211中,40G IP核中需要将设置为对应的数值。原创 2024-12-17 09:30:00 · 1618 阅读 · 0 评论 -
Xilinx UltraScale+DDR4项目开发(三)——DDR4器件选型与MIG IP的配置
数据在时钟的双边沿采样,故有效数据传输频率为时钟频率的两倍,数据传送频率(等效频率),实际应用中测试时关注的时钟频率,下图中的3200MHz/2666MHz/2400MHz。DDR4器件选型,需要根据项目中内存的容量需求,读写速率,成本等各方面考虑,对于FPGA开发者,需要根据DDR4 MIG的IP控制器的性能进行选型,并配置。这个跟硬件上DDR4的颗粒有关系了,在上面IP配置中,数据位宽选择64,也就是4 * 16,硬件上使用了4个DDR4颗粒,故4 * 1GB=4GB,是DDR4的内存总容量。原创 2024-12-16 04:00:00 · 2012 阅读 · 0 评论 -
Xilinx UltraScale+DDR4项目开发(二)——DDR4 MIG的时钟网络
对应原语中的数值一一对应进行计算,以CLKOUT0为标准来计算,CLKIN_PERIOD_NS_MMCM数值表示的是输入时钟的周期,单位NS,9996ps,这个是通过DDR4的IP的用户界面设置的,也就是100M的差分时钟输入,外部硬件需要提供100M的差分时钟。从代码底层来看,ddr4_phy_v2_2_0_pll和ddr4_v2_2_17_infrastructure这两个模块实现了DDR4控制的所有时钟的产生,下面的仿真中表示的div_clk表示CLKOUT0,riu_clk表示CLKOUT6。原创 2024-12-15 02:15:00 · 1823 阅读 · 0 评论 -
Xilinx UltraScale+DDR4项目开发(一)——DDR4 MIG的ip接口信号
本节目录一、DDR4 SDRAM MIG的IP核接口信号二、时钟和复位三、DDR4的AXI数据接口四、DDR4的物理接口五、校准信号六、往期文章链接本节内容一、DDR4 SDRAM MIG的IP核接口信号BD,block design,创建后添加DDR4 SDRAM MIG的IP,图中的IP接口信号包括以下部分:时钟和复位,DDR4的AXI数据接口,DDR4的物理接口和校准信号等。至于如何新建BD,并添加MIG的ip,此处不做详细说明了,毕竟网上开源的教程已经很多了,理论上有手就会(原创 2024-12-14 18:46:27 · 1995 阅读 · 0 评论 -
vivado时序报告中slack是如何计算的?如何优化时序?
当然上述时序报告的问题,源时钟和目的时钟clock tx_clk_out[0]的时钟周期约束不一致,原因是因为IP核里面xdc约束的clock tx_clk_out[0]为6.4ns,在用户的xdc中约束为8ns,导致两者的时序不一致,从而不满足要求。若为红色,也就是所谓的时序违例,也有人称为时序爆红,需要优化时序,从而保证该路径的布线满足时序要求。从源时钟路径报告上,可以得到Tclk1的数值,其延时的总和为源时钟的路径延时,对应建立时间计算公式的Tclk1,即Tclk1=8.329ns。原创 2024-12-11 10:30:00 · 1157 阅读 · 0 评论 -
UltraScale+FPGA中Serdes的多lane对齐异常解决方案
接收到涉及到各种各样的复位,先满足QPLL或者CPLL的初始化复位,之后才是GTY的复位,因为涉及到多lane对齐,因此需要关注pg211手册中的接收侧状态。其实这种思路参考了看门狗复位的方法,计数到10s,检查下接收RX的状态,若异常则复位。高速Serdes的调试,两大难度:一是时钟,输入高速bank的参考时钟选择,QPLL、CPLL选择,用户侧时钟的选择,在前面的文章中已经介绍过了;二是复位,尤其是接收侧复位,涉及到各种模块的复位,而且还有复位时序的要求。问题来了,什么时候需要对RXPMA层进行复位?原创 2024-12-10 10:45:00 · 1340 阅读 · 0 评论 -
vivado+modelsim联合仿真中,如何修改do文件实现仿真代码和综合代码独立工作?
笔者习惯使用第二种方式,通过“+define+SIM +define+SIM_SPEED_UP”来实现Modelsim平台下仿真代码生效。由此在vivado+modelsim联合仿真中,修改do文件实现仿真代码和综合代码独立工作。刚开始用起来也挺舒服的,只需要在头文件中define,同时还需要在verilog中进行头文件引用,否则verilog中的宏定义并不会生效。但是最近仿真40G ETH MAC PCS+PMA的IP时候,发现此种方式并没有让IP核底层的仿真define实现,底层代码未引用头文件。原创 2024-12-09 10:30:00 · 1080 阅读 · 0 评论 -
低速接口项目之串口Uart开发(十一)——zynq PL侧串口在线升级
乒乓操作接收BIN二进制文件,基于双RAM的乒乓操作,大致思路如下:rx接收字节,先写入RAM1固定长度字节,再写入RAM2固定长度字节,两个RAM交叉写入。整个操作流程中,需要的设计技巧不少,包括:基本功能串口接收和发送、接收端的乒乓操作缓存、DDR3的AXI接口写入操作以及发送端的ascii log输出功能。PC电脑端的上位机QT,通过串口发送BIN文件至FPGA的PL端,PL端通过乒乓操作将BIN二进制文件写入PS侧DDR3,待接收完成后,PL侧启动PS侧的QSPI实现flash的更新。原创 2024-12-08 10:30:00 · 989 阅读 · 0 评论 -
低速接口项目之串口Uart开发(十)——基于EMIO的自定义PL串口实现zynq的在线升级
PL侧的普通IO要实现PS侧的QSPI的在线更新,此处提供两种实现思路:一是通过EMIO路由的方式,采用PS侧成熟的UART和QSPI的控制,从而实现PS侧的QSPI flash的更新。二是在PL侧实现一个串口的接收BIN文件的驱动,更新至PS侧的QSPI中,从而实现PS侧的QSPI flash的更新。本文实现的是上述中的思路一,PS通过EMIO路由至PL侧的普通IO管脚,在PS的软核开发串口更新flash的驱动,前面系列文章已经描述过了,此处不再进行详细描述。原创 2024-12-07 11:15:00 · 1042 阅读 · 0 评论 -
低速接口项目之串口Uart开发(九)——如何通过ps侧的串口实现zynq的在线升级(二)
在线升级的核心在于读取BIN二进制文件,然后通过串口发送到Zynq端,当然需要封装一个BIN文件字节长度寄存器,用于通知zynq的ps端,写入QSPI flash的文件字节长度。串口中断接收字节,在回调函数中,接收字节长度寄存器,之后再存储该字节长度的数据,提供给QSPI驱动模块进行更新Flash。用户界面开发,基于QT组件和C++的界面,软件开源比硬件开源舒服多了,对于个人来说,不需要考虑各种性能,通常都是功能性软件。通过QT上位机连接串口,导入文件,然后点击启动更新,发送字节长度寄存器的数据帧。原创 2024-12-06 06:30:00 · 910 阅读 · 0 评论 -
低速接口项目之串口Uart开发(八)——如何通过ps侧的串口实现zynq的在线升级(一)
串口在线升级,就是通过I/O外设中的UART和QSPI控制器,将生成的BIN文件更新的Procesing System(PS侧)外挂的Flash中,断电从QSPI flash中重启,实现固件的更新。串口升级,通过串口传输待更新的BIN文件,利用Uart的控制器,采用中断的方式,实现BIN文件的传输。当然,此处的串口可以是ps侧固定的IO接口,也可以通过EMIO实现PL侧的扩展,从而实现串口在线升级,此部分后期进行开发验证。在PS侧开发,对QSPI Flash的读写操作,离不开底层的控制器。原创 2024-12-05 13:11:15 · 960 阅读 · 0 评论 -
低速接口项目之串口Uart开发(七)——如何在FPGA项目中实现自适应波特率串口功能
串口波特率Baud,具体定义此处不再进行描述,常用的波特率数值有115200、57600、38400、19200、9600等,FPGA开发项目使用中通常都是固定的波特率与上位机串口通信,上位机可以选择对应的FPGA波特率才能实现通信,否则通信失败。FPGA内部默认使用115200的波特率,通过寄存器写入指定的波特率数值从而实现不同波特率切换。串口波特率和FPGA波特率设置为115200,通过查询得到FPGA波特率为115200,对寄存器40000000进行读取,数值为aaaabbbb,与默认值一致。原创 2024-11-23 00:15:00 · 1220 阅读 · 0 评论 -
低速接口项目之串口Uart开发(六)——zynq系列ps-pl端uart实现共享Axilite内部寄存器的读写
但是评估资源的时候需要注意总共就只有两个uart的硬核控制器,如果需要更多的串口,思路有很多种,比如:ps侧通过GPIO扩展串口,移植串口驱动;PS串口COM8,再次读取寄存器32’h40000004,数值为32’h55556666。硬件上,PL侧和PS侧各一路串口,其中COM5为PL侧串口,COM8为PS侧串口。串口中断函数操作,对串口的数据处理,均在此处完成,个人理解,进入中断处理函数后进行业务处理,也就是所有的串口收发以及解析组帧等均在中断处理函数中实现。①PL侧读写测试验证+②PS侧读写测试验证。原创 2024-11-22 06:30:00 · 1458 阅读 · 0 评论 -
低速接口项目之串口Uart开发(五)——QT实现Uart串口寄存器读写工具
串口寄存器读写工具,为了方便FPGA开发者通过串口访问内部AXIlite的寄存器,属于轻量级的debug工具,界面中包括基本的串口配置项,寄存器读操作,寄存器写操作,发送显示和接收显示,均以HEX的格式进行写入和显示。LED控制寄存器,可读可写,基地址+偏移地址为32’h8000_0000+32’h0000_0008=32’h8000_0008,寄存器初始值为32’h0000_0000。只读寄存器的验证结果,读取32’h8000_0000寄存器的数值为32’haaaa_bbbb。读写测试寄存器的验证结果。原创 2024-11-21 04:30:00 · 1133 阅读 · 0 评论 -
低速接口项目之串口Uart开发(四)——UART串口实现FPGA内部AXILITE寄存器的读写控制
在uart_frame_ctrl中,当PC电脑端发送寄存器写数据帧时,解析来自串口的数据,生成wishbone的写控制,完成axilite的寄存器的写入操作,同时,将接收的数据组帧后,并发送至PC串口显示。用过AXILITE总线的FPGA开发者,或多或少都了解这个总线信号五个通道,相当多,也有直接逻辑控制各个通道的信号,而此处的思路是引入wishbone总线,通过控制wishbone总线的读写,借助于成熟开源的wishbone总线转换AXI总线的模块,从而实现axilite寄存器的读写控制。原创 2024-11-20 06:30:00 · 1098 阅读 · 0 评论 -
低速接口项目之串口Uart开发(三)——串口发送模块和接收模块
数据在刚刚发生变化和即将发生变化的这一时期,数据极有可能不稳定的,在这两个时间段采集数据,很有可能得到错误的结果,因此判定这两段时间的电平无效,采集时直接忽略。采样6次的结果分别1/1/1/1/0/1/,则取电平结果为 1,若为 0/0/1/0/0/0,,则取电平结果为 0,当6次采样结果中 1 和 0 各占一半(各 3 次),则可判断当前通信线路环境非常恶劣,数据不具有可靠性,不进行处理。目前,入门时候参考的小梅哥的,当然串口收发模块设计思路也是参考小梅哥的,个人感觉还可以,后期模块修改成同步复位。原创 2024-11-19 04:15:00 · 964 阅读 · 0 评论 -
低速接口项目之串口Uart开发(二)——FIFO实现串口数据的收发回环测试
串口数据的发送,则以FIFO的非空标志作为启动,读取FIFO内的数据并通过uart_tx将数据发送出去。串口数据的收发回环测试,最简单的硬件测试是把Tx和Rx连接在一起,然后上位机进行发送和接收测试,但是需要考虑到串口数据的缓存,通常软件驱动侧也会实现串口接收数据的缓存,或者通过一个环形buffer进行串口接收数据的处理。上板验证,采用的是正点原子的7020开发板,自定义GPIO作为串口的收发pin,通过CH340的模块与PC的usb端口相连,上位机软件进行串口数据的发送与接收。帧头为a1b2c3d4。原创 2024-11-18 06:30:00 · 1638 阅读 · 0 评论 -
低速接口项目之串口Uart开发(一)——串口UART
在 RS-232 标准中,最常用的配置是八个数据位+无奇偶校验+一个停止位,按照一个完整的字节包括一位起始位、8 位数据位、一位停止位即总共十位数据来算,要想完整的实现这十位数据的发送,就需要 11个波特率时钟脉冲,第 1 个脉冲标记一次传输的起始,第 11 个脉冲标记一次传输的结束。通常FPGA与电脑之间采用RS-232的串行数据通信接口标准,也就是计算机串行接口,显示COMX等,可以采取拔插串口的操作,通过在PC电脑的设备管理器下查看新增的串口COM,在上位机上进行连接。原创 2024-11-17 00:47:52 · 1235 阅读 · 0 评论 -
往期文章汇总——总有一本适合你水平的书籍,书籍推荐一至四十
书籍推荐往期链接。原创 2024-10-30 10:30:00 · 525 阅读 · 0 评论 -
往期文章汇总——射频测量+无线通信+软件无线电+6G科普
三、软件无线电系列往期链接。一、射频测量系列往期链接。二、无线通信系列往期链接。四、6G科普系列往期链接。原创 2024-10-29 11:45:00 · 934 阅读 · 0 评论 -
AXI协议之AXILite开发设计(结束篇)
至此AXI4Lite系列完结,本工程只是简单的使用AXI4lite,但已经具备工程应用思想,完全可以移植至项目中,只需要对wb的主机控制和自定义从机的寄存器内容即可。,关注可获取相关源码,定期更新有关FPGA的项目以及开源项目源码,包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等。1、通过wb转换axilite接口,便于操作使用,不同控制axilite的各个通道;2、对宏定义的Slaver0/Slaver1的自定义寄存器进行操作,从而实现寄存器的读写控制。原创 2023-08-01 17:28:11 · 257 阅读 · 0 评论 -
AXI协议之AXILite开发设计(四)—Block Design使用
(10)先右键assign后,按系统要求,slaver0寄存器地址范围为0x00000000—0x0000FFFF,内部寄存器使用必须在此范围;(5)双击AXI interconnect,修改slaver和master num个数,适配工程应用场景,本文用例采用1Master-2Slaver应用,因为对应互联模块应该设置为1Slave和2Master,才能适配成功。(11)设置成功后,如图所示,代码开发中需保证各个Slaver用户使用的寄存器在此范围配置内,否则无法响应。(3)点击“+”,add ip。原创 2023-07-30 00:12:07 · 2354 阅读 · 0 评论 -
AXI协议之AXILite开发设计(三)
本章内容介绍工程中使用的AXI Crossbar ip以及Block Design中可使用的AXI interconnect组件,通过搭建工程使用。AXI Crossbar IP生成,尤其是基地址仲裁选择,需要注意适配项目的应用场景,本文采用1Master2Slaver应用场景,工程2个Slaver对应至AXI Crossbar IP的两个Master互联,即2个Master。工程1个Master对应至AXI Crossbar IP的slaver互联,即1个Slaver。②各类型器件的AXI性能。原创 2023-07-28 11:17:33 · 1984 阅读 · 3 评论 -
AXI协议之AXILite开发设计(二)
(byte_index*8) +: 8],byte_index = 0/1/2/3,对应[0:7],[8:15],[16:23],[24:31],对应32位数据。axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB],即axi_awaddr[3:2],写通道地址的高两位。在写地址通道有效、写地址通道准备信号ok以及写数据通道有效、写数据通道准备信号ok时,寄存器写使能slv_reg_wren才有效。写数据操作时候,使用三个通道,即写地址、写数据、写响应通道。原创 2023-07-27 19:36:46 · 367 阅读 · 0 评论 -
AXI协议之AXILite开发设计(一)
本设计主要介绍AXILite的设计开发,通过一个主机Master读写控制两个从机Slaver(通过基地址进行寄存器地址偏移),从而实现外设寄存器的控制。包括:IP的生成、各通道的信号讲解,以及基地址的使用。原创 2023-07-26 14:38:12 · 835 阅读 · 0 评论 -
基于fpga的图像处理之图像灰度化处理(Vivado+Modelsim+Matlab联合仿真验证)
本文采用两种算法进行灰度处理,平均法和加权均值法;加权均值法采用了直接公式求解和查找表两种方式验证;同时FPGA设计中三个设计技巧,可用于工程项目借鉴,一是宏定义参数化设计;二是generate if参数定义;三是调用xilinx的rom原语实现ROM核,省去ip核的调用原创 2023-05-11 15:10:39 · 4108 阅读 · 0 评论 -
Vivado Block Design中IP使用技巧
Utility Vector Logic在Block design可用于向量的与、或、异或、非。比如:复位信号,外部提供低有效的信号,DDR MIG IP复位高有效,可使用此IP转换输入MIG原创 2022-04-10 09:00:00 · 3503 阅读 · 0 评论 -
Vivado关联NotePad编译器
Vivado自带编译器,多数人使用起来不方便,推荐链接外部编译器,比如NotePad(笔者自己所习惯的)、Vs等均可指令—编译器电脑路径 [file name] — E:\FPGA\Notepad++/NotePad++.exe [file name]原创 2022-04-09 09:00:00 · 4506 阅读 · 1 评论 -
Vivado封装IP实例
工具平台:Vidado 2020器件型号:xczu7ev-ffvc1156-2-i封装步骤如下:1、新建vivado工程,添加源码2、Tools——Create and Package New IP,选择Package your current project(封装当前工程pro)注意:Create AXI4 Peripheral 封装AXI4外设接口3、Create New IP4、设置IP信息在主界面Package IP页中,点击左侧Packaging Steps一栏中的“Iden原创 2022-04-08 15:05:56 · 4895 阅读 · 0 评论 -
HDMI RGB_TO_DVI模块
HDMI RGB_TO_DVI模块一、模块简介在HDMI视频数据传输过程中,将24位的RGB888格式的图像,在编码和并串转换后,以TMDS数据输出至HDMI。HDMI_Encoder模块负责对数据进行编码,HDMI_Serializer模块对编码后的数据进行并串转换,最后通过OBUFDS转化成TMDS差分信号传输。二、逻辑代码module HDMI_RGBtoDVI( input wire [00:00] i_pixel_clk , //像素数据输入时钟原创 2021-08-05 11:38:07 · 2291 阅读 · 0 评论 -
HDMI并串转换模块
HDMI并串转换模块一、简介在HDMI视频数据传输过程中,需要对来自TMDS编码后的10bit并行像素数据转换成1bit串行数据。从理论上讲,生成一个10倍于像素时钟的快时钟对其装换发送。关于OSERDESE2原语模块,一方面可以实现DDR的功能,即它在五倍时钟频率的基础上又实现了双倍数据速率,因此逻辑代码使用一个5倍的时钟频率,即可实现10倍的时钟频率。另一方面,由于一个OSERDESE2模块只能实现最多8:1的转换率,通过位宽扩展实现了10:1 的并串转换(如图)。注意:OSERDESE2位宽扩原创 2021-08-05 10:57:46 · 1262 阅读 · 0 评论 -
TMDS数据编码算法
TMDS,Transition Minimized Differential Signaling,即最小化差分传输信号,在DVI(数字视频接口,只能传输视频)和HDMI(音视频均可传输)协议中用于传输音视频数据,使用差分信号传输高速串行数据。1、TMDS接口TMDS连接从逻辑功能上可以划分成两个阶段:编码和并串转换。在编码阶段,编码器将视频源中的像素数据、HDMI的音频/附加数据,以及行同步和场同步信号分别编码成10位的字符流。然后在并串转换阶段将上述的字符流转换成串行数据流,并将其从三个差分输出通道发原创 2021-05-06 10:38:20 · 6600 阅读 · 4 评论 -
跨时钟域之全握手信号(Verilog)
跨时钟域之全握手信号(Verilog)1、Verilog的实现实现多位数据的跨时钟域传输,存在一定的数据延迟module class_3_clka_clkb#( parameter Width = 31 )( input wire i_clk_a , input wire i_clk_b原创 2021-04-07 14:13:29 · 3724 阅读 · 0 评论 -
同步FIFO和异步FIFO的Verilog实现(代码仿真实现)
同步FIFO和异步FIFO的Verilog实现一、同步FIFO1、同步FIFO的Verilog实现module class_6_fifo#( parameter Width = 16, parameter Depth = 4 )( input wire i_clk , input wire原创 2021-04-01 17:02:29 · 1530 阅读 · 0 评论 -
二进制码和格雷码转换的Verilog实现
二进制码和格雷码之间的转换一、二进制码与格雷码转换原理(1)二进制码转换格雷码二进制码 Bi Bi-1 Bi-2 ... B1 B0 ^ ^ ^ ^ ^ 0 Bi Bi-1 ... B2 B1格雷码 Gi Gi-1 Gi-2 ... G原创 2021-04-01 15:45:10 · 1649 阅读 · 0 评论 -
Lattice Diamond在线调试Reveal Analyzer使用教程
Lattice Diamond在线调试Reveal Analyzer使用教程1、插入Reveal Inserter,直接点击Reveal Inserter图标或者从Tools打开Reveal Analyzer。2、在“Trace Signal Setup”窗口设置采样信号、时钟、深度等,将“Design Tree”中需要抓取的信号“COME_5V_EN”等拖入“Trace”窗口,将采样时钟“CPLD_50M_CLK”拖入“Sampl Clock”,并设置采样深度“Buffer Depth”。3、原创 2021-03-30 17:40:17 · 7345 阅读 · 3 评论 -
FPGA中复位情况汇总(五种)
原创 2021-03-30 09:10:32 · 423 阅读 · 0 评论