来讲一讲面试必问的异步FIFO设计!

异步FIFO设计可以说是数字IC设计工程师面试时必问的一个问题了,也是我们经常使用但是又往往被忽略的一个东西,今天就展开详细说一说不同深度(2^N或者非2^N)异步FIFO的设计思想;

一:2^N深度异步FIFO设计

1:应用场景

异步FIFO用来在两个异步时钟域之间传输数据,如下图中是两个系统,分别为“system A”和“systemY”,从X向Y传输数据,两个系统工作在不同的时钟域。

 system X使用 xclk将数据写入FIFO,systemY使用yclk将数据读出,fifo full和fifo_empty分别负责监控上溢(overflow)和下溢(underflow)情况

fifo_full 指示上溢出情况,拉高时数据不应再写入FIFO,否则会将FIFO内的数据覆盖掉;

fifo_empty指示下溢出情况,拉高时不应该再读取FIFO,否则会读出垃圾数据

与握手信号不同,异步FIFO用于对性能要求较高的设计中,尤其是时钟延时比系统资源更为重要的环境中。

2:异步FIFO的结构

与同步FIFO设计原理相似,异步FIFO的结构也可以分为三个部分,如图中所示,fifo write control。fifo read control和fifo memory,其中fifo write control和fifo read control分别工作在wr_clk和rd_clk时钟域,fifo memory工作在wr_clk和rd_clk时钟域。

fifo write control:写指针产生,满信号产生,读指针同步器

fifo read control:读指针产生,空信号产生和写指针同步器

fifo memory:缓存数据

3:关键设计

3.1:异步fifo和同步fifo的差异,异步fifo特点:

      1:fifo memory工作在两个时钟域

      2:wr_ctrl和rd_ctrl工作在不同的时钟域

      3:读/写指针经过两级同步器后会存在延迟

       异步FIFO不能再使用“计数器”产生fifo空,满信号,原因在于计数器不能被两个时钟同时驱动,此时只能通过比较读,写指针来产生空,满信号,将读指针同步到写时钟域,与写指针比较产生满信号,将写指针同步到读时钟域,与读指针比较产生空信号。

        读写指针的同步都需要跨时钟域传输,若使用握手信号的方式同步指针,效率很低;加入指针仍然使用“二进制编码”,使用两级同步器同步指针,可能会出现采样的亚稳态导致用于比较的指针出现错误。

         如指针从“111-000”经过两级同步器,可能的结果有8种可能,每一个比特都可能存在采样错误,错误的指针会导致fifo空,满信号异常拉起。

# 读指针同步错误,FIFO满信号未正常拉高,继续写FIFO会覆盖原数据,导致数据传输错误;

写指针同步错误,FIFO空信号为正常拉高,继续读FIFO会读出垃圾数据,导致数据传输错误;

因此异步fifo的指针在跨时钟做同步时应该避免使用二进制编码!

3.2:格雷码

实现异步fifo指针同步的一种方式是使用gray code,格雷码是“单位间距码”,即相邻之间只有1bit不同,格雷码与二进制码的对应关系如下图中所示,格雷码有一下几个特点:

# 单位间距码:相邻值之间只有1bit不同;

# 中心对称:除MSB外,其余bit中心对称;

 指针采用格雷码经过两级同步器同步很少会出现亚稳态,此外取样后的值最多只有1bit出现错误,但该错误不会影响空,满信号的产生,考虑格雷码读写指针采样错误的情况:

# 读指针若采样错误:相邻gray code只有1bit不同,若采样出现亚稳态会出现两种情况,一是采样值保持不变,同步的读指针小于当前的真实值,fifo full会提前拉高,此时不会出现overflow;二是采样值采样成功,同步的读指针等于当前的真实值,两种结果都不会影响fifo_full的正确产生;

# 写指针采样错误:写指针同理,一是同步的写指针小于当前的真实值,fifo empty会提前拉高,虽然还有数据未读出,但是这种情况也不会造成underflow;二是同步的写指针党羽当前的真实值,两种结果都不会影响fifo empty的正确产生。

3.3:同步器对指针进行同步操作带来的影响:

比较读写指针的目的是产生FIFO的空满信号,相比同步FIFO,异步FIFO在两个时钟域分别比较读写指针,读/写指针都需要经过两级同步器;

3.3.1:FIFO的 “假满”

由于读指针同步到写时钟域存在2*T_wclk的延迟,此时写时钟域采样到的rd_ptr_sync必然小于或者等于读时钟域的rd_ptr,rd_ptr_sync小于rd_ptr的情况如图所示,wr_ptr追赶上rd_ptr_sync (wr_ptr和rd_ptr_sync都转换为gray code) ,最高位不同其余未相同,此时fifo full信号拉高,但是实际上FIFO内还有两个地址空间可以写入数据,这种情况就是FIFO的假满,fifo的假满虽然阻止了数据的写入,但是对数据的准确性是没有影响的,只有在FIFO实际已经满了但是没有阻止数据写入才会出现overflow(原本有效的数据被覆盖)

3.3.2 :FIFO的 “假空” 

由于写指针同步到读时钟域存在2*T_rclk的延迟,此时读时钟域采样到的wr_ptr_sync小于等于读时钟域的wr_ptr。wr_ptr_sync小于等于wr_ptr的情况如图所示,wr_ptr_sync等于rd_ptr(指针均以转换为gray code),所有比特位均相等,此时会拉高fifo_empty信号。FIFO的“假空”虽然在实际有数据的情况下拉高了FIFO的空信号,阻止了数据的读出,但是对数据的准确性是没有影响的,直到读时钟域看到的写指针变化才会拉低FIFO的空信号。只有在FIFO为空的时候没有阻止读操作才会产生问题,即underflow问题;

3.4 格雷码和二进制码的转换

读、写指针有二进制码转为格雷码后经两级同步器同步到写、读时钟域进行指针的比较以产生FIFO的空、满信号,下面将给出格雷码与二进制码相互转换的方法。

二进制转换gray code:

gray code转换二进制:

3.5 读,写指针的产生

读写指针的产生有两种方法,一种是直接使用gray code计数器产生读写指针,一种是使用二进制码计数器产生读写指针,再将读写指针转换为格雷码用于跨时钟域的同步,下面将分析这两种设计方法:

3.5.1格雷码计数器

格雷码计数器的结构如图所示,由格雷码转换二进制,二进制加法器和二进制码转格雷码组成;

从面积和工作频率两个方面分析该设计。

# 面积:格雷码转二进制、二进制转格雷码的组合逻辑,格雷码指针寄存器;

# 工作频率:寄存器输入信号的组合逻辑较为复杂,该电路工作在较高频率可能存在时序违例的情况。

3.5.2 二进制码计数器

二进制码计数器的结构如图所示,由二进制转格雷码,二进制码寄存器和格雷码寄存器组成;

 从面积和工作频率两个方面分析该设计;

面积:二进制转格雷码,两个寄存器;

工作频率:寄存器输入只有加法器或者二进制转格雷码,组合逻辑延迟较小,该电路可以工作在较高的频率;

3.6:空,满信号的产生

FIFO的空,满信号通过比较读,写指针可以得到,下文直接给出最常用的设计下FIFO的空,满信号如何产生。
采用二进制计数,将二进制转换为gray code进行指针比较产生full或者empty信号;

2^N deep 的fifo 指针计数信号和转换后的gray code信号位宽需要N+1位。

按照格雷码的特性:

FIFO EMPTY:读写指针完全相同时;

FIFO FULL:对比二进制码的满判定原则,最高位不同,其余位相同即认为满,但是如下图所示的情况如果格雷码也采用这种方式判断就会出现问题;

当rd_ptr和wr_ptr相等时FIFO为空,wr_ptr加一后,wr_ptr和rd_ptr的最高位不同,其余位相同,按照二进制的判满原则此时FIFO为满,但此时FIFO并没有满,所以二进制码的FIFO判断满的方法不适用于格雷码。

那格雷码该怎么判满呢?很简单,双格雷码计数器可以很好的解决这个问题,计数器的最高位用于区分写指针比读指针多回绕一次,次高位用于确定写指针的真实位置,FIFO满需要满足三个条件:

1:同步后的读指针rd_ptr_sync的MSB应该与下一个写指针的格雷码wr_gtemp的MSB应该不同;

2:写时钟域两位MSB异或应与读指针一样; 

3:剩下的LSB都应该一样;

总结上述三点其实就是:读写指针的最高位和次高位相反,其余位均相同;

4:大容量异步FIFO设计

大容量同步FIFO是使用SRAM作为FIFO memory实现的,大容量异步FIFO仍可以使用该方法,不过更为常用的方法是使用“大容量同步FIFO和小容量异步FIFO”级联来实现的。原因在于异步FIFO的功能只是跨时钟域传输数据,同步FIFO更适合缓存数据,结合这两种FIFO的特点将其级联,得到大容量异步FIFO;

5:代码实现

5.1:async_fifo_top

//=================================================================================
// module      : async_fifo_gray_cnt.v
// description : asynchronous fifo , pointer generate by gray counter
//=================================================================================

module async_fifo(
    wclk,
    wrst_n,
    wr_en,
    wr_data,
    rclk,
    rrst_n,
    rd_en,
    rd_data,
    fifo_full,
    fifo_empty    
);

//=================================================================================
// parameter & localparam
//=================================================================================

//=================================================================================
// parameter
parameter FIFO_DATA_WIDTH       = 16;
parameter FIFO_DEPTH            = 16;

//=================================================================================
// localparam
localparam FIFO_ADDR_WIDTH      = clog2(FIFO_DEPTH);
localparam FIFO_PTR_WIDTH       = FIFO_ADDR_WIDTH + 1;

//=================================================================================
// I/O
//=================================================================================
input                               wclk;
input                               wrst_n;
input                               wr_en;
input   [FIFO_DATA_WIDTH-1:0]       wdata;

input                               rclk;
input                               rrst_n;
input                               rd_en;
output  [FIFO_DATA_WIDTH-1:0]       rdata;

output                              fifo_full;
output                              fifo_empty;

//=================================================================================
// signal
//=================================================================================

// ---- fifo mem ----
wire    [FIFO_ADDR_WIDTH-1:0]       waddr;
wire    [FIFO_ADDR_WIDTH-1:0]       raddr;

// ---- wr_sync_cell ----
wire    [FIFO_PTR_WIDTH-1:0]        rptr_g;
wire    [FIFO_PTR_WIDTH-1:0]        rptr_g_sync;

// ---- rd_sync_cell ----
wire    [FIFO_PTR_WIDTH-1:0]        wptr_g;
wire    [FIFO_PTR_WIDTH-1:0]        wptr_g_sync;

// ---- wr_ptr_full ----



//=================================================================================
// main body
//=================================================================================

//=================================================================================
// 1. fifo_mem
// 2. wr_sync_cell
// 3. rd_sync_cell
// 4. wptr_full
// 5. rptr_empty

//=================================================================================
// fifo_mem

fifo_mem #(
    .DSIZE          (FIFO_DATA_WIDTH        ),
    .FIFO_DEPTH     (FIFO_DEPTH             )
)
u_fifo_mem(
    .raddr          (raddr                  ),
    .rdata          (rdata                  ),
    .wclk           (wclk                   ),
    .wr_en          (wr_en                  ),
    .waddr          (waddr                  ),
    .wdata          (wdata                  ),
    .fifo_full      (fifo_full              )
);

//=================================================================================
// wr_sync_cell

sync_cell #(
    .DSIZE          (FIFO_DATA_WIDTH)
)
u_rd_ptr_sync(
    .dat_i          (rptr_g         ),
    .clk_o          (wclk           ),
    .rst_n_o        (wrst_n         ),
    .dat_o          (rptr_g_sync    )
);

//=================================================================================
// rd_sync_cell

sync_cell #(
    .DSIZE          (FIFO_DATA_WIDTH)
)
u_wr_ptr_sync(
    .dat_i          (wptr_g         ),
    .clk_o          (rclk           ),
    .rst_n_o        (rrst_n         ),
    .dat_o          (wptr_g_sync    )
);

//=================================================================================
// wptr_full

wptr_full #(
    .FIFO_DEPTH     (FIFO_DEPTH     )
)
u_wptr_full (
    .wclk           (wclk           ),
    .wrst_n         (wrst_n         ),
    .wr_en          (wr_en          ),
    .waddr          (waddr          ),
    .wptr_g         (wptr_g         ),
    .rptr_g_sync    (rptr_g_sync    ),
    .fifo_full      (fifo_full      )
);

//=================================================================================
// rptr_empty

rptr_empty #(
    .FIFO_DEPTH     (FIFO_DEPTH     )
)
u_rptr_empty(
    .rclk           (rclk           ),
    .rrst_n         (rrst_n         ),
    .rd_en          (rd_en          ),
    .raddr          (raddr          ),
    .wptr_g_sync    (wptr_g_sync    ),
    .rptr_g         (rptr_g         ),
    .fifo_empty     (fifo_empty     )
);

endmodule;

5.2 async_fifo_mem

//=================================================================================
// module      : fifo_mem.v
// description : register dpram
//=================================================================================

module fifo_mem (
    raddr,
    rdata,
    wclk,
    wr_en,
    fifo_full,
    waddr,
    wdata
);

// ==========================================================================
// parameter
// ==========================================================================
parameter DSIZE             = 8;
parameter FIFO_DEPTH        = 16;

// ==========================================================================
// localpara
// ==========================================================================
localparam FIFO_ADDR_WIDTH  = $clog2(FIFO_DEPTH);

// ==========================================================================
// I/O
// ==========================================================================
input   [FIFO_ADDR_WIDTH-1:0]       raddr;
output  [DSIZE-1:0]                 rdata;

input                               wclk;
input                               wr_en;
input   [FIFO_ADDR_WIDTH-1:0]       waddr;
input   [DSIZE-1:0]                 wdata;

// ==========================================================================
// signal define
// ==========================================================================
reg     [DSIZE-1:0]                 fifo_mem[FIFO_DEPTH-1:0];

// ==========================================================================
// main body
// ==========================================================================

// ==========================================================================
// write fifo_mem
always@(posedge wclk) begin
    if((wr_en == 1'b1) && (fifo_full != 1'b1)) begin
        fifo_mem[waddr] <= wdata;
    end
end

// ==========================================================================
// read fifo_mem
assign rdata = fifo_mem[raddr];


endmodule

5.3  sync_cell

//=================================================================================
// module      : sync_cell.v
// description : 2-stage synchronizer
//=================================================================================

module sync_cell(
    dat_i,
    clk_o,
    rst_n_o,
    dat_o
);

//=================================================================================
// parameter & localparam
//=================================================================================
parameter DSIZE                 = 16;

//=================================================================================
// I/O
//=================================================================================
input   [DSIZE-1:0]                 dat_i;

input                               clk_o;
input                               rst_n_o;
output  [DSIZE-1:0]                 dat_o;

//=================================================================================
// signal
//=================================================================================

// ---- temp flip-flop ----
reg     [DSIZE-1:0]                 dat_i_ff1;
reg     [DSIZE-1:0]                 dat_i_ff2;

//=================================================================================
// main body
//=================================================================================

always@(posedge clk_o or negedge rst_n_o) begin
    if(rst_n_o == 1'b0) begin
        dat_i_ff1 <= {DSIZE{1'b0}};
        dat_i_ff2 <= {DSIZE{1'b0}};
    end
    else begin
        dat_i_ff1 <= dat_i;
        dat_i_ff2 <= dat_i_ff1;
    end
end

assign dat_o = dat_i_ff2;

endmodule

5.4 wptr_full

//=================================================================================
// module      : wptr_full.v
// description : async_fifo write ctrl
//=================================================================================

module wptr_full(
    wclk,
    wrst_n,
    wr_en,
    waddr,
    wptr_g,
    rptr_g_sync,
    fifo_full
);

//=================================================================================
// parameter & localparam
//=================================================================================
parameter FIFO_DEPTH        = 16;

localparam FIFO_ADDR_WIDTH  = clog2(FIFO_DEPTH) ;
localparam FIFO_PTR_WIDTH   = FIFO_ADDR_WIDTH + 1;

//=================================================================================
// I/O
//=================================================================================
input                               wclk;
input                               wrst_n;
input                               wr_en;
output  [FIFO_ADDR_WIDTH-1:0]       waddr;

output  [FIFO_PTR_WIDTH-1:0]        wptr_g;
input   [FIFO_PTR_WIDTH-1:0]        rptr_g_sync;

output                              fifo_full;

// ==========================================================================
// signal define
// ==========================================================================
reg     [FIFO_PTR_WIDTH-1:0]        wptr_b;
reg     [FIFO_PTR_WIDTH-1:0]        wptr_g;
reg                                 fifo_full;

wire    [FIFO_PTR_WIDTH-1:0]        wptr_bnext;
wire    [FIFO_PTR_WIDTH-1:0]        wptr_gnext;

//=================================================================================
// main body
//=================================================================================

// ---- binary count ----

assign wptr_bnext   = wptr_b + (wr_en & (~fifo_full));
assign waddr        = wptr_b[FIFO_ADDR_WIDTH-1:0];

always @(posedge wclk or negedge wrst_n) begin
    if(wrst_n == 1'b0)begin
        wptr_b <= {FIFO_PTR_WIDTH{1'b0}};
    end
    else begin
        wptr_b <= wptr_bnext;
    end
end

// ---- binary to gray ----
assign wptr_gnext = (wptr_bnext >> 1) ^ (wptr_bnext);

always @(posedge wclk or negedge wrst_n) begin
    if(wrst_n == 1'b0) begin
        wptr_g <= {FIFO_PTR_WIDTH{1'b0}};
    end
    else begin
        wptr_g <= wptr_gnext;
    end

end

// ---- fifo full -----
// three necessary condition
assign fifo_full_val = (wptr_gnext == {~rptr_g_sync[FIFO_PTR_WIDTH-1:FIFO_PTR_WIDTH-2],
                                       rptr_g_sync[FIFO_PTR_WIDTH-3:0]});

always@(posedge wclk or negedge wrst_n) begin
    if(wrst_n == 1'b0) begin
        fifo_full <= 1'b0;
    end
    else begin
        fifo_full <= fifo_full_val;
    end
end



endmodule

5.5 rptr_empty

//=================================================================================
// module      : rptr_empty.v
// description : async_fifo read ctrl
// data        : 2022/3/2
// author      : souther meditating
//=================================================================================

module rptr_empty(
    rclk,
    rrst_n,
    rd_en,
    raddr,
    wptr_g_sync,
    rptr_g,
    fifo_empty
);

//=================================================================================
// parameter & localparam
//=================================================================================
parameter FIFO_DEPTH        = 16;

localparam FIFO_ADDR_WIDTH  = clog2(FIFO_DEPTH) ;
localparam FIFO_PTR_WIDTH   = FIFO_ADDR_WIDTH + 1;

//=================================================================================
// I/O
//=================================================================================
input                               rclk;
input                               rrst_n;

input                               rd_en;
output  [FIFO_ADDR_WIDTH-1:0]       raddr;

input   [FIFO_PTR_WIDTH-1:0]        wptr_g_sync;
output  [FIFO_PTR_WIDTH-1:0]        rptr_g;

output                              fifo_empty;

// ==========================================================================
// signal define
// ==========================================================================
reg     [FIFO_PTR_WIDTH-1:0]        rptr_b;
reg     [FIFO_PTR_WIDTH-1:0]        rptr_g;

wire    [FIFO_PTR_WIDTH-1:0]        rptr_bnext;
wire    [FIFO_PTR_WIDTH-1:0]        rptr_gnext;

wire                                fifo_empty_val;
reg                                 fifo_empty;

//=================================================================================
// main body
//=================================================================================

// ---- binary count ----

assign rptr_bnext       = rptr_b + (rd_en & (~fifo_empty));
assign raddr            = rptr_b[FIFO_ADDR_WIDTH-1:0];

always @(posedge rclk or negedge rrst_n) begin
    if(rrst_n == 1'b0) begin
        rptr_b <= {FIFO_PTR_WIDTH{1'b0}};
    end
    else begin
        rptr_b <= rptr_bnext; 
    end
end

// ---- binary to gray ----

assign rptr_gnext = (rptr_bnext >> 1) ^ rptr_bnext;

always@(posedge rclk or negedge rrst_n) begin
    if(rrst_n == 1'b0) begin
        rptr_g <= {FIFO_PTR_WIDTH{1'b0}};
    end
    else begin
        rptr_g <= rptr_gnext;
    end
end

// ---- fifo empty ----
assign fifo_empty_val = (rptr_gnext == wptr_g_sync);

always @(posedge rclk or posedge rrst_n) begin
    if(rrst_n == 1'b0) begin
        fifo_empty <= 1'b1;
    end
    else begin
        fifo_empty <= fifo_empty_val;
    end
end

endmodule

二:非2^N深度异步FIFO设计

三:参考文章

硬件架构的艺术:异步FIFO设计_fifo级联_南风在冥想的博客-CSDN博客

数字IC前端设计进阶 - 知乎 (zhihu.com)

【《硬件架构的艺术》读书笔记】03 处理多个时钟(3) - Magnolia666 - 博客园 (cnblogs.com)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

git和github学习

一、什么是git和github? 二、学会使用github desktop应用程序 初始使用&#xff1a; 一开始我们是新账户&#xff0c;里面是没有仓库的&#xff0c;需要手动创建一个仓库。此时&#xff0c;这个仓库是创建在本地仓库里面&#xff0c;需要用到push命令&#xff08;就是那个pub…

现代C++中的从头开始深度学习【2/8】:张量编程

一、说明 初学者文本&#xff1a;此文本需要入门级编程背景和对机器学习的基本了解。张量是在深度学习算法中表示数据的主要方式。它们广泛用于在算法执行期间实现输入、输出、参数和内部状态。 在这个故事中&#xff0c;我们将学习如何使用特征张量 API 来开发我们的C算法。具…

Android Studio实现简单ListView

效果图 MainActivity package com.example.listviewtest;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle; import android.widget.ListView;import com.example.listviewtest.adapter.PartAdapter; import com.example.listviewtest.bean.PartB…

【Spring Cloud 六】Hystrix熔断

这里写目录标题 系列文章目录背景一、Hystrix是什么服务雪崩服务容错的相关概念熔断器降级超时控制限流 二、会什么要有Hystrix三、如何使用Hystrix进行熔断处理整体项目代码服务提供者pom文件yml配置文件启动类controller 服务消费者pom文件yml配置文件启动类feignhystrixcont…

网络安全(黑客)零基础入门

导语 什么是 Web 安全&#xff1f;我又该如何入门学习它呢&#xff1f;学习过程中又应注意哪些问题呢&#xff1f;... 或许你的心中有着这样的疑问、不过别着急&#xff0c;本文会为你一一解答这些问题。 正文 定义 Web 安全&#xff0c;顾名思义便是由保障 Web 应用能够持续…

Windows新版文件资源管理器经常在后台弹出的临时解决方案

禁用组策略自动刷新 运行gpedit.msc找到计算机配置->管理模板->系统->组策略找到 “关闭组策略的后台刷新”启用 参考 https://answers.microsoft.com/en-us/windows/forum/all/windows-11-most-recently-opened-explorer-window/26e097bd-1eba-4462-99bd-61597b5…

【计算机网络】socket编程

文章目录 1. 网络通信的理解2.进程PID可以取代端口号吗&#xff1f;3. 认识TCP协议4. 认识 UDP协议5. socket编程接口udp_server.hpp的代码解析socket——创建 socket 文件描述符Initserver——初始化1.创建套接字接口&#xff0c;打开网络文件bind——绑定的使用 2.给服务器指…

鸿蒙智联再出发,携手伙伴共赢空间智能化,创造无限可能

新空间&#xff0c;再出发&#xff0c;HarmonyOS Connect伙伴峰会完 2023年8月5日&#xff0c;HarmonyOS Connect伙伴峰会在东莞如期举办&#xff0c;峰会以《一起创造无限可能 新空间 再出发》为主题&#xff0c;深度解读了鸿蒙智联商业模式全面升级以来&#xff0c;给伙伴带来…

Qt拖放事件与拖放操作笔记dragEnterEvent,dropEvent

1 介绍 拖放事件主要用于处理MIME数据&#xff0c;该数据是用于在发送电子邮件时&#xff0c;附加多媒体数据&#xff08;即拖拽一个文件放入邮件中&#xff0c;事件文件的上传&#xff09;。 2 示例 a&#xff09;使用简化步骤声明拖放事件成员函数&#xff1a; b&#xff09;…

C#与C/C++交互(1)——需要了解的基础知识

【前言】 C#中用于实现调用C/C的方案是P/Invoke&#xff08;Platform Invoke&#xff09;&#xff0c;让托管代码可以调用库中的函数。类似的功能&#xff0c;JAVA中叫JNI&#xff0c;Python中叫Ctypes。 常见的代码用法如下&#xff1a; [DllImport("Test.dll", E…

IPv6地址分类,EUI-64转换规则

1、可聚合的单全球单播地址Global Unique Address&#xff1a; Aggregate global unicast address&#xff0c;前3位是001&#xff0c;即2000::/3&#xff0c;目前IANA已经将一部分可聚合全球单播进行了专门使用&#xff0c;如&#xff1a;2001::/16用于IPV6互联网&#xff0c;…

流量分析日志查看

一流量分析 buuctf wireshark 从题目出发&#xff0c;既然是上传登录信息&#xff0c;就直接过滤post请求&#xff0c;即搜索 http.request.methodPOST&#xff0c;因为上传用户登录信息使用的一定是http里的post方法 模式过滤 http.request.method “GET” http.request.…

无涯教程-Perl - getpriority函数

描述 此函数返回进程(PRIO_PROCESS),进程组(PRIO_PGRP)或用户(PRIO_USER)的当前优先级。 参数WHICH指定要为PRIO_PROCESS,PRIO_PGRP或PRIO_USER之一设置优先级的实体,WHO是要设置的进程ID或用户ID。 WHO的值为0定义了当前流程,流程组或用户。这会在不支持系统getpriority()函…

Springboot后端通过路径映射获取本机图片资源

项目场景&#xff1a; 项目中对图片的处理与查看是必不可少的&#xff0c;本文将讲解如何通过项目路径来获取到本机电脑的图片资源 如图所示&#xff0c;在我的本机D盘的图片测试文件夹(文件夹名字不要有中文)下有一些图片&#xff0c; 我们要在浏览器上访问到这些图片&#…

RISC-V基础之函数调用(二)栈与寄存器(包含实例)

堆栈是一种后进先出&#xff08;LIFO&#xff09;的队列&#xff0c;用于存储函数调用时的临时数据和现场数据。堆栈指针sp&#xff08;寄存器2&#xff09;是一个普通的RISC-V寄存器&#xff0c;按照惯例&#xff0c;指向堆栈的顶部。堆栈从高地址向低地址增长&#xff0c;即当…

【UE4 RTS】04-Camera Pan

前言 本篇实现了CameraPawn的旋转功能。 效果 步骤 1. 打开项目设置&#xff0c;添加两个操作映射 2. 打开玩家控制器“RTS_PlayerController_BP”&#xff0c;新建一个浮点型变量&#xff0c;命名为“PanSpeed” 在事件图表中添加如下节点 此时运行游戏可以发现当鼠标移动…

WEB集群——负载均衡集群

目录 一、 LVS-DR 群集。 1、LVS-DR工作原理 2、LVS-DR模式的特点 3、部署LVS-DR集群 3.1 配置负载调度器&#xff08;192.168.186.100&#xff09; 3.2 第一台web节点服务器&#xff08;192.168.186.103&#xff09; 3.3 第二台web节点服务器&#xff08;192.168.186.…

Q-Vision+Kvaser CAN/CAN FD/LIN总线解决方案

智能联网技术在国内的发展势头迅猛&#xff0c;随着汽车智能化、网联化发展大潮的到来&#xff0c;智能网联汽车逐步成为汽车发展的主要趋势。越来越多整车厂诉求&#xff0c;希望可以提供本土的测量软件&#xff0c;特别是关于ADAS测试。而Softing中国推出的Q-Vision软件不仅可…

f12 CSS网页调试_css样式被划了黑线怎么办

我的问题是这样的 class加上去了,但是样式不生效,此时可能是样式被其他样式覆盖了, 解决方案就是 给颜色后边添加一个!important

Docker的入门与使用

什么是Docker&#xff1f; docker官网 简介与概述 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#x…
最新文章