• FIFO(二) —— 手写同步和异步FIFO


    本文针对大佬手写FIFO设计进行学习与总结。

    一、verilog实现同步FIFO

    module SCFIFO1
    
    //定义FIFO位宽和深度
    
    #(
    	 parameter   DATA_WIDTH = 'd8  ,							//FIFO位宽
        parameter   DATA_DEPTH = 'd16 ,							//FIFO深度
    	 parameter   full_almost = 'd14  ,							//将满的位置
        parameter   empty_almost = 'd2 							//将空的位置
    )
    
    
    (
        
        input [DATA_WIDTH-1:0] data,
    	 input clk,
    	 input rst_n,
    	 input wrreq,
    	 input rdreq,
    	 
    	 
    	 output empty,	    //空标志,高电平表示当前FIFO读空
    	 output reg almost_empty,
    
    	 output full ,       //满标志,高电平表示当前FIFO写满
    	 output reg almost_full,
    	 
    	 output [$clog2(DATA_DEPTH) :0]usedw, //$clog2是以2为底取对数	
    	 
    	 output  reg [DATA_WIDTH-1:0] q
    
    );
    
    reg [$clog2(DATA_DEPTH) :0] fifo_cnt; //fifo计数器,对fifo内的数据进行计数
    
    reg [DATA_WIDTH - 1 : 0] fifo_buffer[DATA_DEPTH - 1 : 0];	//用二维数组实现RAM	
    
    reg [$clog2(DATA_DEPTH) - 1 : 0]	wr_addr;				//写地址
    reg [$clog2(DATA_DEPTH) - 1 : 0]	rd_addr;				//读地址
    
    
    
    //写操作:计算写地址
    
    always @ (posedge clk or negedge rst_n) 
        if(!rst_n)
    	     wr_addr <= 0;
    	 else if(wrreq && !full)begin
    	     wr_addr <= wr_addr + 1'b1;
    		  fifo_buffer[wr_addr]<=data;
    		  end
    
    //读操作:计算读地址
    
    always @ (posedge clk or negedge rst_n) 
        if(!rst_n)
    	     rd_addr <= 0;
    	 else if(rdreq && !empty)begin //读使能且未读空
    	     rd_addr <= rd_addr + 1'b1;
    		  q <=fifo_buffer[rd_addr];
    		  end
    		  
    //usedw,计数器来计算fifo中的数据个数
    
    always @ (posedge clk or negedge rst_n) begin
    	if (!rst_n)
    		fifo_cnt <= 0;
    	else begin
    		case({wrreq,rdreq})									   //拼接读写使能信号进行判断
    			2'b00:fifo_cnt <= fifo_cnt;						//不读不写
    			
    			2'b01:	                               	   //只读不写
    				if(fifo_cnt != 0)				   			   //fifo没有被读空
    					fifo_cnt <= fifo_cnt - 1'b1;   			//fifo个数-1
    					
    			2'b10:                                       //只写不读
    				if(fifo_cnt != DATA_DEPTH)         			//fifo没有被写满
    					fifo_cnt <= fifo_cnt + 1'b1;   			//fifo个数+1
    					
    			2'b11:fifo_cnt <= fifo_cnt;	           			//读写同时
    			default:;                              	
    		endcase
    	end
    end
    assign usedw = fifo_cnt;
    //依据计数器状态更新指示信号
    //还可设置将满和将空的位置,来判断,从而得到almost_full和almost_emputy信号
    assign full  = (fifo_cnt == DATA_DEPTH) ? 1'b1 : 1'b0;		//空信号
    assign empty = (fifo_cnt == 0)? 1'b1 : 1'b0;				//满信号
    
    //将满
    always @ (posedge clk or negedge rst_n) 
    	if (!rst_n)
    	    almost_full  <= 0;
    	else if(wrreq && fifo_cnt == full_almost-1) //计数0开始,因此-1
    	    almost_full  <= 1;
    	else
    	    almost_full  <= 0;
    	    
    //将空
    always @ (posedge clk or negedge rst_n) 
    	if (!rst_n)
    	    almost_empty  <= 0;
    	else if(rdreq && fifo_cnt == empty_almost+1)//计数0开始,因此+1
    	    almost_empty  <= 1;
    	else
    	    almost_empty  <= 0;
    	    
    
    endmodule 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110

    tb测试

    `timescale 1ns/1ps
    
    module fifo_tb(); //对同步fifo仿真
    
    parameter   DATA_WIDTH = 'd8  ;							//FIFO位宽
    parameter   DATA_DEPTH = 'd16 ;							//FIFO深度
    
    
    
    	reg	[DATA_WIDTH-1:0]  data;
       reg	  clk;
    	reg     rst_n;
    	reg     wrreq;
    	reg	  rdreq;
    	
    	wire empty;
       wire full;
       wire almost_full;
    	wire almost_empty;
    	wire	[DATA_WIDTH-1:0]  q;
    	wire [$clog2(DATA_DEPTH) :0]usedw;
    
    
    SCFIFO1  
    #(
    	.DATA_WIDTH	(DATA_WIDTH),			
       .DATA_DEPTH	(DATA_DEPTH)			
    
    )
    u1(	
    	.data(data),
    	.clk(clk),
    	.rst_n(rst_n),
    	.wrreq(wrreq),
    	
    	.rdreq(rdreq),
    	
    	.almost_empty(almost_empty),
    	.almost_full(almost_full),
    	
    	.empty(empty),
    	.full(full),	
    	
    	.q(q),
    	.usedw(usedw)
    
    );
    
    
    //产生激励
    
    initial begin
        clk = 0;
    	 rst_n = 0;
    	 
    	 data =  0;
    	 
    	 rdreq = 0;
    	 wrreq = 0;
    	 #10;
    
    
    //将FIFO写满	 
    	 	repeat(16)begin
    			rst_n = 1;
    			wrreq = 1;
    			#20;
    			data = data + 1;
    		end
    		wrreq = 0;
    
    		repeat(16)begin
    			rdreq = 1;
    			#20;
    			data = data + 1;
    		end
    		rdreq = 0;
    		
    		#500;
    		$stop;
    
    	 
    end
    
    
    always #10 clk = ~clk;
    
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    modelsim波形仿真

    先wrreq=1,写入16个数据,将fifo写满,后rdreq = 1 ,将16个数据读出。
    波形如下:
    红色框中是定义的四个参数,FIFO位宽,深度以及将满和将空的位置。
    在这里插入图片描述

    分析写相关信号:
    当wrreq = 1开始写数据,因此usedw开始+1,表示已用fifo的深度,当使用了14个深度的时候,是将满的位置,因此almost_full=1。同时当usedw=16,说明用了16深度,fifo写满,full=1。
    在这里插入图片描述
    分析读相关信号:
    当rdreq = 1读数据,因此usedw开始从16不断-1,当usedw=2,表示将空的位置,因此almost_emoty=1。同时当usedw=0,说明fifo读空,empty=1。
    可看到最终q的输出数据是0-15。实现了数据的先入先出。
    在这里插入图片描述

    二、verilog实现异步fifo

    异步fifo

    第一节介绍了同步fifo的设计方法,但同步fifo读写采用同一时钟,而异步fifo读写时钟不同,下面对其进行分析。参考

    异步fifo设计的重点也是写满和读空的判断,参考大佬的博文,得到了如下的判断方式:

    “写满”的判断: 将读指针同步到写时钟域,再与写指针判断
    .
    “读空”的判断:将写指针同步到读时钟域,再与读指针判断

    如下是假读空:
    左图:读指针没有超过写指针,说明没有读空。
    右图:写指针同步到读时钟域需要T时间,经过T时间后,虽然在读时钟域中读写指针相同(读空),但左图才是实际的情况,因此这种情况是假读空。
    在这里插入图片描述
    如下是假写满:
    左图:写指针没有超过读指针一圈,说明没有写满
    右图:读指针同步到写时钟域需要T时间,经过T时间后,虽然在写时钟域中写指针超过了读指针一圈(写满),但左图才是实际的情况,因此这种情况是假写满。
    在这里插入图片描述

    格雷码

    1、降低亚稳态
    跨时钟域中可能出现亚稳态,最终导致fifo功能错误,由于格雷码每次只有一位发生变化,因此我们引入格雷码来降低亚稳态现象的出现。

    2、格雷码判断空满
    将格雷码进行同步,同步后的格雷码转换成二进制后比较。

    实现

    1、分别构造读、写时钟域下的读、写指针,指针位数需拓展一位(最高位作为指示位,判断写指针是否超过读指针一圈)。
    分别将读、写指针从二进制码转换成格雷码

    二进制码转格雷码:

    assign 	wr_ptr_g = wr_ptr ^ (wr_ptr >> 1);
    assign 	rd_ptr_g = rd_ptr ^ (rd_ptr >> 1);
    
    • 1
    • 2

    2、将格雷码形式的读指针同步到写时钟域,将格雷码形式的写指针同步到读时钟域

    //将读指针的格雷码同步到写时钟域,来判断是否写满
    always @ (posedge wr_clk or negedge wr_rst_n) begin
    	if (!wr_rst_n)begin
    		rd_ptr_g_d1 <= 0;										//寄存1拍
    		rd_ptr_g_d2 <= 0;										//寄存2拍
    	end				
    	else begin												
    		rd_ptr_g_d1 <= rd_ptr_g;								//寄存1拍
    		rd_ptr_g_d2 <= rd_ptr_g_d1;								//寄存2拍
    	end	
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    //将写指针的格雷码同步到读时钟域,来判断是否读空
    always @ (posedge rd_clk or negedge rd_rst_n) begin
    	if (!rd_rst_n)begin
    		wr_ptr_g_d1 <= 0;										//寄存1拍
    		wr_ptr_g_d2 <= 0;										//寄存2拍
    	end				
    	else begin												
    		wr_ptr_g_d1 <= wr_ptr_g;								//寄存1拍
    		wr_ptr_g_d2 <= wr_ptr_g_d1;								//寄存2拍		
    	end	
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3、在写时钟域判断“写满”:格雷码形式的读写指针高2位相反,其余位相等——写满

    在读时钟域判断“读空”,格雷码形式的读写指针高2位相等,其余位也相等——读空

    //写满
    assign	full  = ( wr_ptr_g == { ~(rd_ptr_g_d2[$clog2(DATA_DEPTH) : $clog2(DATA_DEPTH) - 1])
    ,rd_ptr_g_d2[$clog2(DATA_DEPTH) - 2 : 0]})? 1'b1 : 1'b0;
    
    • 1
    • 2
    • 3
    //读空
    assign	empty = ( wr_ptr_g_d2 == rd_ptr_g ) ? 1'b1 : 1'b0;
    
    • 1
    • 2

    大佬写的都很清晰,可以学习一下,完整代码

    //异步FIFO
    module	DCFIFO1
    #(
        parameter   DATA_WIDTH = 'd8,   //FIFO位宽                    
        parameter   DATA_DEPTH = 'd8 	//FIFO深度							
    )		
    (		
    //写有关信号		
    	input							wr_clk		,			//写时钟
    	input							wr_rst_n	,       		//低电平有效的写复位信号
    	input							wr_en		,       		//写使能信号,高电平有效	
    	input	[DATA_WIDTH-1:0]		data_in		,     //写入的数据
    	
    //读有关信号			
    	input							rd_clk		,			//读时钟
    	input							rd_rst_n	,       		//低电平有效的读复位信号
    	input							rd_en		,				//读使能信号,高电平有效						                                        
    	output	reg	[DATA_WIDTH-1:0]	data_out	,	//输出的数据
    	
    //空满标志					
    	output							empty		,				//空标志,高电平表示当前FIFO已被写满
    	output							full		    			//满标志,高电平表示当前FIFO已被读空
    );                                                              
     
    
    //用二维数组实现RAM
    reg   [DATA_WIDTH - 1 : 0]			   fifo_buffer[DATA_DEPTH - 1 : 0]; //深度为8,位宽为8的fifo
    
    //定义读写指针,且指针位数拓展一位,用来作为空满指示位
    
    reg  [$clog2(DATA_DEPTH) : 0]		wr_ptr;						//写指针,二进制(5位)
    reg  [$clog2(DATA_DEPTH) : 0]		rd_ptr;						//读指针,二进制
    
    wire [$clog2(DATA_DEPTH) : 0]		wr_ptr_g;					//写指针,格雷码
    wire [$clog2(DATA_DEPTH) : 0]		rd_ptr_g;					//读指针,格雷码
    
    
    reg  [$clog2(DATA_DEPTH) : 0]		wr_ptr_g_d1;				//写指针格雷码在读时钟域下打1拍
    reg  [$clog2(DATA_DEPTH) : 0]		wr_ptr_g_d2;				//写指针格雷码在读时钟域下打2拍
    reg  [$clog2(DATA_DEPTH) : 0]		rd_ptr_g_d1;				//读指针格雷码在写时钟域下打1拍
    reg  [$clog2(DATA_DEPTH) : 0]		rd_ptr_g_d2;				//读指针格雷码在写时钟域下打2拍
    	
    
    wire [$clog2(DATA_DEPTH) - 1 : 0]	wr_ptr_true;			//真实写指针,作为写ram的地址(4位)
    wire [$clog2(DATA_DEPTH) - 1 : 0]	rd_ptr_true;			//真实读指针,作为读ram的地址
     
    //地址指针从二进制转换成格雷码
    assign  wr_ptr_g = wr_ptr ^ (wr_ptr >> 1);					
    assign  rd_ptr_g = rd_ptr ^ (rd_ptr >> 1);
     
    //读写RAM地址赋值
    assign  wr_ptr_true = wr_ptr [$clog2(DATA_DEPTH) - 1 : 0];	//拓展一位的写指针,去除最高位
    assign  rd_ptr_true = rd_ptr [$clog2(DATA_DEPTH) - 1 : 0];	//拓展一位的读指针,去除最高位
     
    //将写指针的格雷码同步到读时钟域,与格雷码读指针判断是否读空
    always @ (posedge rd_clk or negedge rd_rst_n) begin
    	if (!rd_rst_n)begin
    		wr_ptr_g_d1 <= 0;										//打1拍
    		wr_ptr_g_d2 <= 0;										//打2拍
    	end				
    	else begin												
    		wr_ptr_g_d1 <= wr_ptr_g;					    //打1拍
    		wr_ptr_g_d2 <= wr_ptr_g_d1;						//打2拍		
    	end	
    end
      
     
     //写操作,更新写地址
    always @ (posedge wr_clk or negedge wr_rst_n) begin
    	if (!wr_rst_n)
    	    wr_ptr <= 0;
    	else if (!full && wr_en)begin								//写使能有效且非满
    		 wr_ptr <= wr_ptr + 1'd1;
    		 fifo_buffer[wr_ptr_true] <= data_in;
    	end	
    end
    
    
    //将读指针的格雷码同步到写时钟域,与格雷码写指针判断是否写满
    
    always @ (posedge wr_clk or negedge wr_rst_n)
        if(!wr_rst_n)begin
    	     rd_ptr_g_d1 <= 0;	
    	     rd_ptr_g_d2 <= 0;	
    	end
    	else begin
    	    rd_ptr_g_d1 <= rd_ptr_g;
    		 rd_ptr_g_d2 <= rd_ptr_g_d1;
    	end
    	 
    //读操作,更新读地址
    always @ (posedge rd_clk or negedge rd_rst_n)
        if(!rd_rst_n)
    	     rd_ptr <= 'd0;
    	 else if(rd_en && !empty) begin								//读使能有效且非空
    	     rd_ptr <= rd_ptr + 1'd1;
    		  data_out <= fifo_buffer[rd_ptr_true];
    	end
    	 
    
    
    //当高2位相等,其余位也相等,读空
    //同步后的格雷码写指针 == 格雷码读指针,FIFO被读空
    assign	empty = ( wr_ptr_g_d2 == rd_ptr_g ) ? 1'b1 : 1'b0;
     
    //当高2位相反且其他位相等时,写指针超过读指针一圈,FIFO被写满
    
    //格雷码写指针 ==  同步后的读指针格雷码高两位取反,再拼接上余下位
    
     
    assign full = (wr_ptr_g == {~(rd_ptr_g_d2[$clog2(DATA_DEPTH) : $clog2(DATA_DEPTH) - 1]),rd_ptr_g_d2[$clog2(DATA_DEPTH) - 2 : 0]});
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    tb文件:

    `timescale 1ns/1ns	//时间单位/精度
    
    module fifo_tb();
     
    parameter   DATA_WIDTH = 8  ;		//位宽
    parameter   DATA_DEPTH = 8 ;		//深度
     
    reg							wr_clk	;		   
    reg							wr_rst_n	;       	
    reg							wr_en		;       		
    reg	[DATA_WIDTH-1:0]	data_in	;        
     
    reg							rd_clk	;			
    reg							rd_rst_n	;       	
    reg							rd_en		;									                                        
    wire  [DATA_WIDTH-1:0]	data_out	;							
    wire						   empty		;			//空标志,高电平表示被写满
    wire						   full		;        //满标志,高电平表示被读空
    
    
    DCFIFO1
    #(
    	 .DATA_WIDTH	(DATA_WIDTH),	
        .DATA_DEPTH	(DATA_DEPTH)
    )
    async_fifo_inst(
    
    	.wr_clk		(wr_clk		),
    	.wr_rst_n	(wr_rst_n	),
    	.wr_en		(wr_en		),
    	.data_in	   (data_in	   ),	
    	.rd_clk		(rd_clk		),               
    	.rd_rst_n	(rd_rst_n	),	
    	.rd_en		(rd_en		),	
    	.data_out	(data_out	),
    	
    	.empty		(empty		),		
    	.full		   (full	   	)
    );
     
    //初始化
    initial begin
    	rd_clk = 1'b0;					
    	wr_clk = 1'b0;					
    	wr_rst_n <= 1'b0;				
    	rd_rst_n <= 1'b0;				
    	wr_en <= 1'b0;
    	rd_en <= 1'b0;	
    	data_in <= 'd0;
    	#5
    	wr_rst_n <= 1'b1;				
    	rd_rst_n <= 1'b1;					
    //写8次,让FIFO写满 	
    	repeat(8) begin
    		@(negedge wr_clk)begin		
    			wr_en <= 1'b1;
    			data_in <= data_in +1 ;	//8个数
    		end
    	end
    	
    //拉低写使能	
    	@(negedge wr_clk)	wr_en <= 1'b0;
    	
    //读8次,将FIFO读空 	
    	repeat(8) begin
    		@(negedge rd_clk) rd_en <= 1'd1;		
    	end
    	
    //拉低读使能
    	@(negedge rd_clk) rd_en <= 1'd0;		
    	
    	//仅写4个数据,此时不读	
    	repeat(4) begin
    		@(negedge wr_clk)begin		
    			wr_en <= 1'b1;
    			data_in <= $random;	//生成8位随机数
    		end
    	end
    	
    //将读使能拉高
    	@(negedge rd_clk) rd_en <= 1'b1;
    	
    
    //同时对FIFO写数据,此时实现同时读写	
    	forever begin
    		@(negedge wr_clk)begin		
    			wr_en <= 1'b1;
    			data_in <= data_in +1 ;	
    		end
    	end	
    
    
    end
     
    
    always #10 rd_clk = ~rd_clk;			//读时钟周期20ns
    always #20 wr_clk = ~wr_clk;			//写时钟周期40ns
     
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    波形:
    在这里插入图片描述

  • 相关阅读:
    nginx代理socket链接集群后,频繁断开重连
    分布式计算实验3 基于PRC的书籍信息管理系统
    【Java第34期】:Bean的六种作用域
    【PowerQuery】在Excel中手动刷新数据连接
    奇异值分解(SVD)原理与在降维中的应用(附带例题讲解)(纯理论)
    【Codecs系列】视频编码中的率失真优化RDO技术
    区块链是什么?
    数据库事务——快照读与当前读
    关于Spring-Boot配置加载顺序解读
    移除元素、分数到小数、整数转罗马数字
  • 原文地址:https://blog.csdn.net/H19981118/article/details/125300999