异步FIFO设计

news2024/11/18 17:23:10

1 FIFO简介

FIFO的本质是RAM,具有先进先出的特性。

FIFO的基本使用原则:空时不能读,满时不能写

FIFO的两个重要参数:宽度和深度

FIFO的两种类型:

  • 同步FIFO:读写时钟相同,通常用来做数据缓存
  • 异步FIFO:读写时钟不同,通常用来做跨时钟域处理

2 异步FIFO设计要点

2.1 空满信号产生的原理

读空信号:

  • 复位的时候(读指针和写指针相等),读空信号有效
  • 读指针赶上写指针的时候,读空信号有效

写满信号:

  • 写指针赶上读指针的时候

2.2 空满指针跨时钟域处理,为什么要使用Gray信号进行同步

空满信号是通过读写指针的比较来产生,但是读指针属于读时钟域,写指针属于写时钟域,读写指针的比较有一个跨时钟域的问题,因此需要对读写指针进行信号的同步:

  • 将写指针同步到读时钟域,然后读指针再和同步后的写指针比较,产生读空信号
  • 将读指针同步到写时钟域,然后写指针再和同步后的读指针比较,产生写满信号

使用格雷码Gray表示的读写指针用两级寄存器同步:
同步过程的亚稳态问题是无法解决的,需要保证即使出现亚稳态也不影响设计的功能

  1. 如果使用二进制编码表示的读写指针进行同步,当出现亚稳态的时候,将会影响设计的功能。
    例如现在将写指针同步到读时钟域,去判断读空信号。写指针0111–>1000,同时有4bit数据发生跳变,在亚稳态的影响下,同步后的写指针的数值可能是0000-1111之间的任何一个数值。本来应该判空的,但是现在没有判空,将会读取错误的数据,使得设计出现问题。
  2. 如果使用格雷码表示的读写指针进行同步,即使出现亚稳态,也不会影响设计的功能。
    格雷码的特点是,相邻的编码之间每次只有1bit数据发生变化。那么这1bit数据如果发生亚稳态会影响设计的功能吗?答案是不会。例如现在还是将写指针同步到读时钟域,去判断读空信号。假设格雷码写指针从0000->0001,写指针同步出错,出错的结果只能是0000->0000,即写指针不变。这种结果最多就是让空信号标志在FIFO不是真正空的时候产生,而不会产生空读的情形。只会影响FIFO的效率,而不会影响到FIFO的功能。
    所以Gray码保证的是同步后的读写指针即使在出错的情形下依然能够保证FIFO功能的正确性

2.3 设计的时候,读写指针的同步至少需要消耗两个时钟周期,肯定会使得空满信号的判断有延迟,会不会导致设计出错??

假设现在将写指针同步到读时钟域再和读指针比较进行FIFO空状态判断,因为在同步写指针时需要时间,而在这个同步的时间内有可能还会写入新的数据,因此同步后的写指针一定是小于或者等于当前实际的写指针,所以此时判断FIFO为空不一定是真空,这样更加保守,一共不会出现空读的情况,虽然会影响FIFO的性能,但是并不会出错。

同理将读指针同步到写时钟域再和写指针比较进行FIFO满状态判断,同步后的读指针一定是小于或者等于当前的读指针,所以此时判断FIFO为满不一定是真满,这样更保守,肯定不会出错。

总结来说异步逻辑转到同步逻辑不可避免需要额外的时钟开销,这会导致满空趋于保守,会稍微有性能损失,但是不会出错

2.4 读写时钟不同频,在同步的过程中,可能会有指针遗漏,是否会影响功能?

异步FIFO两端的时钟不是同频的,或者读快写慢,或者读慢写快,慢的时钟域同步到快的时钟域不会出现漏掉指针的情况,但是将指针从快的时钟域同步到慢的时钟域时可能会有指针遗漏。

举例:假设读慢写快

进行满标志判断的时候,需要将读指针同步到写时钟域,因为写时钟快,不会发生读指针同步遗漏的情况,但是由于同步需要消耗至少两个时钟周期,导致读指针同步延迟,读时钟域rd_ptr=3,但是写时钟域的sync_rd_ptr=2,这样可能会导致满标志信号提前产生,满并非真满,但是不影响FIFO功能。

进行空标志判断的时候,需要将写指针同步到读时钟域,因为读时钟慢,会发生写指针同步遗漏的情况,不用关心漏掉哪几个,而是担心漏掉的指针是否会对设计产生影响,比如写指针从0写到10,期间读时钟域只同步捕捉到了3、5、8这三个写指针而漏掉了其他指针。当同步到8这个写指针时,真实的写指针可能已经写到10 ,相当于在读时钟域还没来得及觉察的情况下,写时钟域可能偷偷写了数据到FIFO去,这样在判断它是不是空的时候会出现不是真正空的情况,漏掉的指针不会对FIFO的逻辑操作产生影响(即不会影响,FIFO在满的时候写数据,空的时候读数据,造成的功能错误),只会影响FIFO的工作效率。

总而言之,实际的读/写指针大于同步之后的读/写指针的数值,这种情况不会影响FIFO的功能,只会影响FIFO的效率。(2.3和2.4)均是这种情况

2.5 二进制转Gray码

原理
在这里插入图片描述
代码
在这里插入图片描述

代码编写思路
大概就是格雷码最高位与二进制码一致,其余各位为二进制码对应位与其相邻的高位异或,如格雷码的第二位为二进制的第二位与二进制码的第三位异或。因此实现代码则为二进制码本身与逻辑右移一位后的二进制码异或即可得。
在这里插入图片描述

2.6 Gray码转二进制

原理
在这里插入图片描述
在这里插入图片描述

代码
在这里插入图片描述

代码编写思路
二进制码的最高位与格雷码最高位保持一致,其余通过自生移位与异或得到,如b[2]为格雷码逻辑右移两位(逻辑右移,最高位补0)再自身四位异或,0与任何数异或均为其本身。
在这里插入图片描述

2.7 读空的条件是写指针等于读指针,写满的条件也是写指针等于读指针,到底如何区分呢?

二进制码判断空满:指针的位宽多定义一位
假设要设计深度为 8 的异步FIFO,此时定义读写指针只需要 3 位(2^3=8)就够用了,
但是我们在设计时将指针的位宽设计成 4 位,最高位的作用就是区分是读空还是写满。
具体判断规则如下:

  • 当最高位相同,其余位相同认为是读空
  • 当最高位不同,其余位相同认为是写满

格雷码判断空满:指针的位宽多定义一位
在设计中判断是读指针是否等于写指针的时候,用的是读写指针的格雷码形式
具体判断规则如下:

  • 当最高位和次高位相同,其余位相同认为是读空

  • 当最高位和次高位不同,其余位相同认为是写满

    因为格雷码是一种镜像码, 例如读指针指向 8,写指针指向 7 ,我们可以知道此时此刻并不是读空状态也不是写满状态;
    (7对应的格雷码0100;8对应得格雷码1100) 但是如果按照二进制码得判断规则,最高位不同,其余位相同,就会误判出现写满信号;因此格雷码判断空满的条件和二进制判断空满的规则不相同。

3 RTL

一个典型的FIFO模块结构如下所示:
在这里插入图片描述
下面是参考上图进行的实现(略有不同):

module async_fifo#(
    parameter   DEPTH   =   16,
    parameter   WIDTH   =   8
)(
    input                   wr_clk  ,
    input                   wr_rstn ,
    input                   wr_en   ,
    input       [WIDTH-1:0] wr_data ,

    input                   rd_clk  ,
    input                   rd_rstn ,
    input                   rd_en   ,
    output  reg [WIDTH-1:0] rd_data ,

    output                  rempty   ,
    output                  wfull    
);


//------------------------------------------------------------------------------------
//                              internal vars         
//------------------------------------------------------------------------------------

reg     [WIDTH-1:0] fifo_ram    [DEPTH-1:0];

reg     [$clog2(DEPTH):0] wr_ptr;
reg     [$clog2(DEPTH):0] rd_ptr;

wire    [$clog2(DEPTH):0] wr_ptr_g;
wire    [$clog2(DEPTH):0] rd_ptr_g;
reg     [$clog2(DEPTH):0] wr_ptr_g_d1;
reg     [$clog2(DEPTH):0] rd_ptr_g_d1;
reg     [$clog2(DEPTH):0] wr_ptr_g_d2;
reg     [$clog2(DEPTH):0] rd_ptr_g_d2;

wire    [$clog2(DEPTH)-1:0] wr_addr;
wire    [$clog2(DEPTH)-1:0] rd_addr;

//------------------------------------------------------------------------------------
//                             wr_ptr && rd_ptr       
//------------------------------------------------------------------------------------

always@(posedge wr_clk or negedge wr_rstn)begin
    if(!wr_rstn)
        wr_ptr <= 0;
    else if(wr_en && !wfull)
        wr_ptr <= wr_ptr + 1'b1;
end

always@(posedge rd_clk or negedge rd_rstn)begin
    if(!rd_rstn)
        rd_ptr <= 0;
    else if(rd_en && !rempty)
        rd_ptr <= rd_ptr + 1'b1;
end


//------------------------------------------------------------------------------------
//                             wfull && rempty       
//------------------------------------------------------------------------------------
assign wr_ptr_g = (wr_ptr >> 1) ^ wr_ptr;
assign rd_ptr_g = (rd_ptr >> 1) ^ rd_ptr;

always@(posedge rd_clk or negedge rd_rstn )begin//write_ptr_g sync to read domain
    if(!rd_rstn)
        {wr_ptr_g_d2,wr_ptr_g_d1} <= 0;
    else 
        {wr_ptr_g_d2,wr_ptr_g_d1} <= {wr_ptr_g_d1,wr_ptr_g};
end

always@(posedge wr_clk or negedge wr_rstn)begin//read_ptr_g sync to write domain
    if(!wr_rstn)
        {rd_ptr_g_d2,rd_ptr_g_d1} <= 0;
    else 
        {rd_ptr_g_d2,rd_ptr_g_d1} <= {rd_ptr_g_d1,rd_ptr_g};
end

assign rempty = (rd_ptr_g == wr_ptr_g_d2);
assign wfull = wr_ptr_g == {~rd_ptr_g_d2[$clog2(DEPTH):$clog2(DEPTH)-1],rd_ptr_g_d2[$clog2(DEPTH)-2:0]};

//------------------------------------------------------------------------------------
//                             write && read       
//------------------------------------------------------------------------------------

assign wr_addr = wr_ptr[$clog2(DEPTH)-1:0];
assign rd_addr = rd_ptr[$clog2(DEPTH)-1:0];

always@(posedge wr_clk)
    if(wr_en && !wfull)
        fifo_ram[wr_addr] <= wr_data;

always@(posedge rd_clk)
    if(rd_en && !rempty)
        rd_data <= fifo_ram[rd_addr];

endmodule

4 Testbench

pattern只写不读、pattern只读不写、pattern写比读快

`timescale 1ns / 1ps

module tb_async_fifo();

//---------------------------------------------------

parameter WIDTH = 3;
parameter DEPTH = 32;

reg                   wr_clk  ;
reg                   wr_rstn ;
reg                   wr_en   ;
reg       [WIDTH-1:0] wr_data ;
reg                   rd_clk  ;
reg                   rd_rstn ;
reg                   rd_en   ;
wire   [WIDTH-1:0]    rd_data ;
wire                  empty   ;
wire                  full    ;

//---------------------------------------------------

initial begin
    wr_clk = 0;
    forever #10 wr_clk = ~wr_clk;//50MHz
end
initial begin
    rd_clk = 0;
    forever #12.5 rd_clk = ~rd_clk;//40MHz
end

initial begin
    rd_rstn = 0;
    wr_rstn = 0;
    #103 ;
    rd_rstn = 1;
    wr_rstn = 1;
end

//pattern1
initial begin
    wr_en   = 0;
    wr_data = 0;
    #203;
    wr_en = 1;
    repeat(32) @(posedge wr_clk)begin
        #1;
        wr_data = wr_data + 1;
    end
    #1;
    wr_en = 0;
end

//pattern2
initial begin
    rd_en = 0;
    #3000;
    rd_en = 1;
    repeat(32) @(posedge rd_clk)begin
    end
    #1;
    rd_en = 0;
end

//pattern3
initial begin
    rd_en = 0;
    wr_en = 0;
    #6000;
    wr_en = 1;
    rd_en = 1;
    repeat(300) @(posedge wr_clk)begin
        #1;
        wr_data = wr_data + 1;
    end
    #1;
    wr_en = 0;
    
    repeat(32) @(posedge rd_clk)begin
    end
    #1;
    rd_en = 0;
end
//---------------------------------------------------

async_fifo#(
    .DEPTH(DEPTH),
    .WIDTH(WIDTH)
) u_async_fifo(
    .wr_clk  (wr_clk  ),
    .wr_rstn (wr_rstn ),
    .wr_en   (wr_en   ),
    .wr_data (wr_data ),
    .rd_clk  (rd_clk  ),
    .rd_rstn (rd_rstn ),
    .rd_en   (rd_en   ),
    .rd_data (rd_data ),
    .empty   (empty   ),
    .full    (full    )
);

endmodule

pattern读比写快

`timescale 1ns / 1ps

module tb_async_fifo_w_slow();

//---------------------------------------------------

parameter WIDTH = 3;
parameter DEPTH = 32;

reg                   wr_clk  ;
reg                   wr_rstn ;
reg                   wr_en   ;
reg       [WIDTH-1:0] wr_data ;
reg                   rd_clk  ;
reg                   rd_rstn ;
reg                   rd_en   ;
wire   [WIDTH-1:0]    rd_data ;
wire                  empty   ;
wire                  full    ;

//---------------------------------------------------

initial begin
    wr_clk = 0;
    forever #10 wr_clk = ~wr_clk;//50MHz
end

initial begin
    rd_clk = 0;
    forever #8 rd_clk = ~rd_clk;//62.5MHz
end

initial begin
    rd_rstn = 0;
    wr_rstn = 0;
    #103 ;
    rd_rstn = 1;
    wr_rstn = 1;
end

//pattern1
initial begin
    wr_en   = 0;
    wr_data = 0;
    #203;
    wr_en = 1;
    repeat(32) @(posedge wr_clk)begin
        #1;
        wr_data = wr_data + 1;
    end
    #1;
    wr_en = 0;
end

//pattern2
initial begin
    rd_en = 0;
    #3000;
    rd_en = 1;
    repeat(32) @(posedge rd_clk)begin
    end
    #1;
    rd_en = 0;
end

//pattern3
initial begin
    rd_en = 0;
    wr_en = 0;
    #6000;
    wr_en = 1;
    rd_en = 1;
    repeat(300) @(posedge wr_clk)begin
        #1;
        wr_data = wr_data + 1;
    end
    #1;
    wr_en = 0;
    
    repeat(32) @(posedge rd_clk)begin
    end
    #1;
    rd_en = 0;
end
//---------------------------------------------------

async_fifo#(
    .DEPTH(DEPTH),
    .WIDTH(WIDTH)
) u_async_fifo(
    .wr_clk  (wr_clk  ),
    .wr_rstn (wr_rstn ),
    .wr_en   (wr_en   ),
    .wr_data (wr_data ),
    .rd_clk  (rd_clk  ),
    .rd_rstn (rd_rstn ),
    .rd_en   (rd_en   ),
    .rd_data (rd_data ),
    .empty   (empty   ),
    .full    (full    )
);

endmodule

pattern读写一样快

`timescale 1ns / 1ps

module tb_async_fifo_w_equal();

//---------------------------------------------------

parameter WIDTH = 3;
parameter DEPTH = 32;

reg                   wr_clk  ;
reg                   wr_rstn ;
reg                   wr_en   ;
reg       [WIDTH-1:0] wr_data ;
reg                   rd_clk  ;
reg                   rd_rstn ;
reg                   rd_en   ;
wire   [WIDTH-1:0]    rd_data ;
wire                  empty   ;
wire                  full    ;

//---------------------------------------------------

initial begin
    wr_clk = 0;
    forever #10 wr_clk = ~wr_clk;//50MHz
end

initial begin
    rd_clk = 0;
    #8;
    forever #10 rd_clk = ~rd_clk;//50MHz
end

initial begin
    rd_rstn = 0;
    wr_rstn = 0;
    #103 ;
    rd_rstn = 1;
    wr_rstn = 1;
end

//pattern1
initial begin
    wr_en   = 0;
    wr_data = 0;
    #203;
    wr_en = 1;
    repeat(32) @(posedge wr_clk)begin
        #1;
        wr_data = wr_data + 1;
    end
    #1;
    wr_en = 0;
end

//pattern2
initial begin
    rd_en = 0;
    #3000;
    rd_en = 1;
    repeat(32) @(posedge rd_clk)begin
    end
    #1;
    rd_en = 0;
end

//pattern3
initial begin
    rd_en = 0;
    wr_en = 0;
    #6000;
    wr_en = 1;
    rd_en = 1;
    repeat(300) @(posedge wr_clk)begin
        #1;
        wr_data = wr_data + 1;
    end
    #1;
    wr_en = 0;
    
    repeat(32) @(posedge rd_clk)begin
    end
    #1;
    rd_en = 0;
end
//---------------------------------------------------

async_fifo#(
    .DEPTH(DEPTH),
    .WIDTH(WIDTH)
) u_async_fifo(
    .wr_clk  (wr_clk  ),
    .wr_rstn (wr_rstn ),
    .wr_en   (wr_en   ),
    .wr_data (wr_data ),
    .rd_clk  (rd_clk  ),
    .rd_rstn (rd_rstn ),
    .rd_en   (rd_en   ),
    .rd_data (rd_data ),
    .empty   (empty   ),
    .full    (full    )
);

endmodule

参考博客:
https://zhuanlan.zhihu.com/p/551351794
https://blog.csdn.net/ZZ2588/article/details/122347438
https://blog.csdn.net/spx1164376416/article/details/121086907
https://zhuanlan.zhihu.com/p/344170711
https://wuzhikai.blog.csdn.net/article/details/121152844
https://blog.csdn.net/JustinLee2015/article/details/106527301/
https://blog.csdn.net/wuzhikaidetb/article/details/123570799
https://blog.csdn.net/weixin_44348260/article/details/119612998

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1011668.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

医疗领域超低温监控,你了解吗?

超低温冰箱在医疗保健领域中扮演着不可或缺的角色。它们被广泛用于存储生物样本、药物和疫苗等温度敏感的医疗物品&#xff0c;以确保这些关键资源的质量和有效性。 然而&#xff0c;温度波动和不稳定性可能会对这些物品造成严重损害&#xff0c;甚至威胁患者的生命。为了应对这…

对话泛微:产业数字化时代,我们需要怎样的OA?

在泛微诞生以后的十年&#xff0c;恰是OA系统的大规模突破。十年间&#xff0c;上百家OA企业的诞生直接将市场推向了鼎盛期。而后又迎来了移动互联网风口&#xff0c;在互联网厂商的冲击之下&#xff0c;传统OA在不断进击的同时&#xff0c;还要进行自我蜕变&#xff0c;成为“…

ppt录制在哪?实用技巧分享!

在现代演示和培训中&#xff0c;PPT演示已经成为越来越流行的一种交流方式。而录制ppt也成为了很多商务演讲、教学讲解、产品演示等场合的必备技能。本文将为您介绍两种常见的ppt录制方式&#xff0c;帮助您轻松录制ppt演示的过程。 ppt录制在哪&#xff1f; ppt是一款流行的演…

操作系统Deepin DTK顺利适配Qt6,从而提供更高效开发体验

据了解&#xff0c;当前deepin DTK(Development ToolKit)已经在近日顺利适配Qt6 (6.4.2)&#xff0c;从而实现全面升级。 据悉&#xff0c;DTK作为 deepin 基于Qt开发的一整套通用开发框架&#xff0c;并且是deepin操作系统中的核心位置。    Multiable万达宝ERP(www.multi…

打败全国百分之99.99的模板方法模式讲解

目录 背景&#xff1a;模板方法定义&#xff1a;步骤&#xff1a;初始版&#xff1a; 每个人都抄卷子&#xff0c;然后抄完写自己的答案第一版&#xff1a;将试卷的题抽象出来第二版&#xff1a;将每个人回答的部分抽象出来第三版&#xff1a;将答题步骤封装出来&#xff08;这…

lenovo联想Legion Y9000P IRX8H 2023款(82WQ)原装出厂Windows11系统

联想拯救者笔记本电脑原厂系统自带网卡、显卡、声卡等所有驱动、出厂主题壁纸、Office办公软件、联想电脑管家等预装程序 链接&#xff1a;https://pan.baidu.com/s/1YBji_oh7xOkq-NxnS8Mm8g?pwdn17o 提取码&#xff1a;n17o 所需要工具&#xff1a;16G或以上的U盘 文件…

el-table 列背景色渐变

最初的想法是&#xff0c;给每一行添加背景色&#xff0c;逐行递减透明度&#xff0c;发现结果比较突兀&#xff0c;效果如下&#xff1a; 如果有需要这种样式的&#xff0c;代码如下&#xff1a; <template><div><el-table:data"tableData":heade…

小麦苗GreenPlum学习大纲

腾讯文档 课程文档内容如下&#xff1a; 小麦苗GreenPlum课程公开课-- 数据库通用学习路线、答疑、培训、考证等&#xff1a;https://docs.qq.com/doc/p/b65bcd7647a9974a94b97fb06d04a089c25a7f0c 小麦苗GreenPlum课程第0节-- 数据库简介、分类、发展、流行度排名等&#xf…

Docker容器化技术(从零学会Docker)

文章目录 前言一、初识Docker1.初识Docker-Docker概述2.初识Docker-安装Docker3.初识Docker-Docker架构4.初识Docker-配置镜像加速器 二、Docker命令1.Docker命令-服务相关命令2.Docker命令-镜像相关命令3.Docker命令-容器相关命令 三、Docker容器的数据卷1.Docker容器数据卷-数…

Python:函数定义的参数

相关阅读 Python专栏https://blog.csdn.net/weixin_45791458/category_12403403.html?spm1001.2014.3001.5482 函数定义就是定义一个用户自定义的函数对象&#xff0c;它的语法的BNF范式如下所示&#xff0c;有关BNF范式的规则&#xff0c;可以参考之前的文章。 funcdef …

asp.net+sqlserver+c#教师工作量计算系统

本课题主要是解决工作量管理管理中的日常中涉及到的问题&#xff0c;目标是使工作量在管理上做到数据的信息化、快速化。 系统在实现上应至少具有如下功能&#xff1a; (1)教师信息管理 该模块包括教师信息的添加、修改。 (2)个人信息 该模块是对用户登录系统后对自己信息的修改…

C-结构体

目录 结构体 定义结构体 第一种方式 定义的同时定义变量名 第三种方式 赋值和初始化 如何取出结构体成员 结构体变量&#xff0c;结构体指针作为函数参数进行传递 结构体运算 结构体 形成了一个新的数据类型 定义结构体 第一种方式 定义一个新的数据类型&#xf…

Unity - Shader Compiled Log

文章目录 吐槽开启 Log Shader Compilation实践资源准备Build ABTesting ScriptShader Compiled Log Project 吐槽 先说一下&#xff0c;最近几天前&#xff0c;纷纷看到 unity install fee 的天才收费方案 真的忍不住吐槽&#xff0c;我只想说&#xff1a; “no zuo no die”…

旋转框/微调按钮的基类--QAbstractSpinBox 类

1、 QAbstractSpinBox 类是 QWidget 类的直接子类&#xff0c;虽然该类不是抽象类&#xff0c;但该类并未提供实 际的功能&#xff0c;仅为旋转框提供了一些外观的形式以及需要子类实现了成员&#xff0c; 也就是说点击微调按钮的上/下按钮&#xff0c;不会使其中的数值有变化。…

Visual Studio批量删除换行

1. 使用ctrlh可以打开替换窗体 2.alte选择窗体中的正则表达式 使用正则表达式&#xff1a; ^\s*$ ^代表行首 $代表行尾 \s代表任意不可见字符&#xff0c;例如空格、Tab等 *代表匹配\s任意次 结果&#xff1a;

002 Linux 权限

前言 本文将会向您介绍关于linux权限方面的内容&#xff0c;包括文件类型&#xff0c;如何切换用户、基本权限、粘滞位等等 Linux具体的用户 超级用户&#xff1a;可以再linux系统下做任何事情&#xff0c;不受限制 普通用户&#xff1a;在linux下做有限的事情。 超级用户的…

安卓预制权限添加规则

android:protectionLevel 可以在 android/frameworks/base/core/res/AndroidManifest.xml查询 signature|preinstalled 加在 这个文件里 privapp-permissions-xx.xml dangerous 加在 default-permissions/default-mega-permissions.xml normal 不需要加 不存在两个文件都加…

【LeetCode-中等题】18. 四数之和

文章目录 题目方法一&#xff1a;双指针&#xff08;定2动2&#xff09; 题目 方法一&#xff1a;双指针&#xff08;定2动2&#xff09; 这题可以参考【LeetCode-中等题】15. 三数之和 区别在于&#xff0c;三数之和只需要用一个for循环定住一个数&#xff0c;然后设置两个前…

类和对象(3)

文章目录 1.回顾上节2. 拷贝构造3. 运算符重载&#xff08;非常重要&#xff09;4. 赋值运算符重载 1.回顾上节 默认成员函数&#xff1a;我们不写&#xff0c;编译器自动生成。我们不写&#xff0c;编译器不会自动生成 默认生成构造和析构&#xff1a; 对于内置类型不做处理对…

mysql远程连接失败

先上结论&#xff0c;只提出最容易忽略的地方 服务器是阿里云、腾讯云等平台&#xff0c;平台本身自带的防火墙没有开启iptables规则中禁用了3306&#xff0c;即使你根本没有启用iptables服务 第二条是最离谱的 从这里可以看到&#xff0c;我服务器并未启用 iptables 服务 但…