数字逻辑设计基础

news2024/12/28 18:51:48

参考:

正点原子逻辑设计指南

状态机FSM

目录

  • 一、组合逻辑
    • 组合逻辑中的竞争-冒险现象
    • 组合逻辑毛刺消除
  • 二、时序逻辑
    • 锁存器
    • 触发器
    • 寄存器
    • 计数器
  • 三、边沿检测电路
  • 四、格雷码转换电路
  • 五、复位电路
    • 数字逻辑需要复位的原因
    • 同步复位
    • 异步复位
    • 异步复位、同步释放
  • 六、状态机
    • 写法
    • 分类
  • 七、偶数分频电路
  • 八、奇数分频电路
  • 九、RAM读写设计
    • 单端口RAM
    • 伪双口RAM
    • 真双口RAM
  • 十、FIFO
  • 十一、异步电路设计
  • 十二、位宽转换电路
    • 整数倍位宽转换
      • 窄到宽
      • 宽到窄
    • 非整数倍位宽转换
      • 窄到宽
  • 十三、调度器
    • 优先级调度器
    • 轮询调度器

一、组合逻辑

组合逻辑:任意时刻的输出只取决于当前时刻的输入,与电路原来的状态无关。

逻辑级数指的是组合逻辑的深度,也就是从组合逻辑输入到输出需要穿过的组合逻辑单元个数。深度越大,组合逻辑越复杂,延迟越大。组合逻辑的逻辑级数不能太长,逻辑级数太长就会导致总的延迟太大。

组合逻辑中的竞争-冒险现象

竞争:信号经不同路径传输到某一汇合点输出的时间有先有后的现象。

冒险:由于竞争而引起电路输出发生瞬间错误的现象,表现为输出端出现了理论上没有的窄脉冲(毛刺)。

信号在器件中传输的时候,所需要的时间是不能精确估计的,在多路信号同时发生跳变的瞬间,组合逻辑的输出有先后顺序,就产生了“竞争冒险”。这时,往往会出现一些不正确的尖峰信号,这些尖峰信号就是“毛刺”。

  • 竞争不一定会产生冒险,但有冒险一定有竞争。
  • 毛刺并非对所有输入都有危害,只要毛刺不出现在时钟的上升沿,就不会对系统造成危害,而当毛刺成为系统的控制信号时就会出现逻辑错误。

如图,y信号最终会得到1个1ns的毛刺信号。
在这里插入图片描述
在这里插入图片描述

组合逻辑毛刺消除

  1. 组合逻辑输出加寄存器:寄存器一般只在时钟跳变沿对输入信号敏感,所以对发生在非时钟跳变沿的毛刺信号,去除效果非常明显。

  2. 信号延时同步法:在两级信号传递的过程中加一个延时环节,从而保证在下一个模块中读取到的数据是稳定后的数据。

  3. 状态机控制:在数据传递比较复杂的多模块系统中,由状态机 在特定的时刻分别发出控制特定模块的时钟信号或者模块使能信号,状态机的循环控制就可以使得整个系统协调运作,同时减少毛刺信号。

  4. 格雷码计数器:格雷码计数器的输出每次只有一位跳变,使用格雷码计数器将避免毛刺的出现。

二、时序逻辑

时序逻辑:任意时刻的输出不仅取决于当前时刻的输入,还取决于电路原来的状态。

时序逻辑由组合逻辑和存储逻辑构成,时序逻辑的存储电路一般由锁存器、触发器和寄存器构成。

锁存器

锁存器(latch)是电平触发的存储单元,数据存储的动作取决于输入时钟(或者使能)信号的电平值,即当锁存器处于使能状态时,输出才会随着数据输入发生变化

锁存器在不锁存数据时,输出端的信号随输入信号变化,就像信号通过一 个缓存器一样;一旦锁存信号起锁存作用,则数据被锁住,输入信号不起作用。

D锁存器能够将单路数据D存入到锁存器的电路。控制信号C=0时,锁存器的输出端Q将维持原状态不变;控制信号C=1时,将单路数据D存入到锁存器中。
在这里插入图片描述

Qn 是指触发器当前逻辑状态也即触发前的状 态,Qn+1 是指触发后的状态。
在这里插入图片描述

当控制信号C为高电平时,输出信号Q将跟随输入信号D的变化而变化;当控制信号C从高电平变为低电平时,输入信号D的状态将会决定锁存器将要锁存的状态。

在这里插入图片描述

设计中要避免产生锁存器,锁存器的危害在于不能过滤毛刺以及由于没有时钟信号,无法对该器件进行时序分析

代码出现latch的主要原因:不带时钟的always中的if或case语句不完整。

触发器

触发器是对脉冲边沿敏感的存储单元电路,它只在触发脉冲的上升沿(或下降沿)瞬间改变其状态。

一般使用最多的是D触发器,该电路是由两个相同的 D 锁存器以及两个非门连接而成的。
设输入信号D=1,CLK=0时,F1选通,F2锁存,Q1为1,Q不变,即前半段输入信号先存入主锁存器;
CLK=1时,F1锁存,F2选通,Q1保持为1,Q=Q1,即后半段将锁存的数据赋值给从锁存器的输出。
这样在CLK信号由 0 变为 1 这样的一个变化周期内,触发器的输出状态只可能改变一次。
在这里插入图片描述
在这里插入图片描述

寄存器

寄存器是多个触发器构成的,可以存储多bit’二进制数据。

触发器并联:
在这里插入图片描述
触发器串联(打拍):
在这里插入图片描述

计数器

计数器由寄存器和加法器组成,可以实现计时、分频等。
在这里插入图片描述
在这里插入图片描述
计数器最低 bit 的 y[0]是每2个周期在循环跳变,而计数器次低 bit的y[1]是每4个周期在循环跳变,计数器最高 bit 的 y[2]是每 8 个周期在循环跳变,若直接把计数器的各个 bit 赋值给一个时钟信号,那么计数器的 y[0]实现的是2分频,计数器的y[1]实现的是4分频,计数器的y[2]实现的是8分频。这个也是最简单和最常用的偶数分频方法。

三、边沿检测电路

边沿检测:检测一个信号的跳变沿,给出一个指示。
检测上升沿:y1 = a & ( ~a_dly1 )
检测下降沿:y2 = ~a & a_dly1
检测双沿:y3 = a ^ a_dly1

四、格雷码转换电路

格雷码:相邻两个数间只有一个数据位发生变化,格雷码适用于 FIFO 的地址处理。

设n 位的二进制:Bn, Bn-1, Bn-2。。。B2, B1 , B0;
n 位的格雷码:Gn, Gn-1, Gn-2。。。G2, G1, G0;

则格雷码转二进制:

Bn =Gn;
Bi-1 = Bi  ^  Gi-1;( i=0,1,2,n-1; )
always @(*) begin
 bin_out[3] = gray_in[3]; 
 bin_out[2] = gray_in[2]^bin_out[3];
 bin_out[1] = gray_in[1]^bin_out[2];
 bin_out[0] = gray_in[0]^bin_out[1];
end

二进制转格雷码:

Gn = Bn;
Gi-1=Bi ^ Bi-1; ( i=0,1,2,n-1; )

assign gray_out = (bin_in >> 1) ^ bin_in;

五、复位电路

复位:将寄存器恢复到默认值。

FPGA内部会有上电复位(POR)电路,FPGA 芯片内部有一个上电检测模块,一旦检测到电源电压超过检测门限后,就产生一个上电复位脉冲(Power On Reset)送给所有的寄存器,这个脉冲会自动作用在各个寄存器的复位端,和功能复位管脚共同控制寄存器的复位。

FPGA重新配置之后也会上电复位。

数字逻辑需要复位的原因

数字电路中寄存器和 RAM 在上电之后默认的状态和数据是不确定的,复位可以把寄存器置到初始状态0。而且如果逻辑进入了错误的状态,通过复位可以把所有的逻辑状态恢复到初始值,否则可能永远运行在错误的状态。

同步复位

同步复位指的是当时钟上升沿检测到复位信号,执行复位操作,有效的时钟沿是前提。

always @ (posedge clk) begin
  if (rst_n == 1'b0)
 	 y <= 1'b0 ;
  else 
 	 y <= b ;
  end

同步复位的优点:

a、有利于仿真器的仿真;
b、可以使所设计的系统成为 100%的同步时序电路,有利于时序分析,而且可综合出较高的 Fmax;
c、由于只在时钟有效电平到来时才有效,所以可以滤除高于时钟频率的复位毛刺

同步复位的缺点:

a、复位信号的有效时长必须大于时钟周期,才能真正被系统识别并完成复位任务。同时还要考虑诸如时钟偏移、组合逻辑路径延时、复位延时等因素(所以复位信号有时需要脉冲展宽,用以保证时钟有效期间有足够的复位宽度);
b、由于大多数的逻辑器件的目标库内的 DFF 都只有异步复位端口,所以,倘若采用同步复位的话,综合器就会在寄存器的数据输入端口插入组合逻辑,这样就会一方面额外增加 FPGA 内部的逻辑资源,另一方面也增加了相应的组合逻辑门时延。

异步复位

异步复位指的是无论时钟沿是否到来,只要复位信号有效,就对系统进行复位。

always @ (posedge clk or negedge rst_n) begin
  if (rst_n == 1'b0)
 	 y <= 1'b0 ;
  else 
 	 y <= b ;
  end

异步复位的优点:

a、大多数目标器件库的 DFF 都有异步复位端口,那么该触发器的复位端口就不需要额外的组合逻辑,这样就可以节省资源;
b、设计相对简单
c、异步复位信号产生和响应都很方便(电路在任何情况下都能复位而不管是否有时钟出现)。

异步复位的缺点:

a、问题出现在复位释放时,而不是有效时,如果复位释放接近时钟有效沿,则触发器的输出可能进入亚稳态(此时 clk 检测到的 rst_n 的状态就会是一个亚稳态,即是0是1是不确定的),从而导致复位失败。
b、可能因为噪声或者毛刺造成虚假复位信号(比如系统正常工作时突然复位)

注意:时钟端口、清零和置位端口对毛刺信号十分敏感,任何一点毛刺都可能会使系统出错。

c、静态定时分析困难,静态时序分析一般是针对同步设计的,都是基于时钟周期来分析时序的。

异步复位、同步释放

推荐使用异步复位、同步释放,既解决了异步复位的亚稳态问题,又解决了同步复位的资源消耗问题。

异步复位同步释放就是在复位信号到来时不受时钟信号同步,而在复位信号释放时受时钟信号同步。

//产生复位rst_sync_n 
always @ (posedge clk or negedge rst_async_n) begin
    if (!rst_async_n) begin 
        rst_s1 <= 1'b0; 
        rst_s2 <= 1'b0; 
    end 
    else begin 
        rst_s1 <= 1'b1; 
        rst_s2 <= rst_s1; //需要额外等1个周期稳定
    end 
 end
 
 //输出的复位信号后续可以直接用来异步复位
 assign rst_sync_n = rst_s2; 
 
 //使用复位rst_sync_n 
 always @ (posedge clk or negedge rst_sync_n ) begin
    if (rst_sync_n == 1'b0)
        y <= 1'b0 ;
    else 
         y <= b ;
 end

六、状态机

写法

一段式:整个状态机写到一个 always 模块里面,在该模块中既描述状态转移,又描述状态的输入和输出。

module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output reg out);//  
 
    parameter A=1'b0, B=1'b1; 
    reg state;
    
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            state <= B;
            out <= 1'b1;
        end
        else begin
            case(state)
                B:begin
                    if(in == 1'b1)begin
                        state <= B;
                        out <= 1'b1;
                    end
                    else begin
                        state <= A;
                        out <= 1'b0;
                    end
                end
                A:begin
                    if(in == 1'b1)begin
                        state <= A;
                        out <= 1'b0;
                    end
                    else begin
                        state <= B;
                        out <= 1'b1;
                    end
                end
                default:begin
                    state <= B;
                    out <= 1'b1;
                end
            endcase
        end
    end
    
endmodule

二段式:用两个 always 模块来描述状态机,其中一个 always 模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出。

module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output reg out);//  
 
    parameter A=1'b0, B=1'b1; 
    reg current_state, next_state;
    
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            current_state <= B;
        end
        else begin
            current_state <= next_state;
        end
    end
 
    always@(*)begin
        case(current_state)
            B:begin
                if(in == 1'b1)begin
                    next_state = B;
                end
                else begin
                    next_state = A;
                end
                out = 1'b1;
            end
            A:begin
                out = 1'b0;
                if(in == 1'b1)begin
                    next_state = A;
                end
                else begin
                    next_state = B;
                end
                out = 1'b0;
            end
        endcase
    end
    
endmodule

三段式:在两个 always 模块描述方法基础上,使用三个 always 模块,一个 always 模块采用同步时序描述状态转移,一个 always 采用组合逻辑判断状态转移条件,描述状态转移规律,另一个 always 模块描述状态输出(可以用组合电路输出,也可以时序电路输出,最好用时序电路)。

module top_module(
    input clk,
    input areset,    // Asynchronous reset to state B
    input in,
    output reg out);//  
 
    parameter A=1'b0, B=1'b1; 
    reg current_state, next_state;
    
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            current_state <= B;
        end
        else begin
            current_state <= next_state;
        end
    end
 
    always@(*)begin
        case(current_state)
            B:begin
                if(in == 1'b1)begin
                    next_state = B;
                end
                else begin
                    next_state = A;
                end
            end
            A:begin
                if(in == 1'b1)begin
                    next_state = A;
                end
                else begin
                    next_state = B;
                end
            end
        endcase
    end
 
    always@(posedge clk or posedge areset)begin
        if(areset)begin
            out <= 1'b1;
        end
        else if(next_state == B)begin
            out <= 1'b1;
        end
        else begin
            out <= 1'b0;
        end
    end
    
endmodule

分类

Mealy 状态机:组合逻辑的输出不仅取决于当前状态,还取决于输入状态。

Mealy型状态机第三段输出采用cur_state
在这里插入图片描述

//==================================================================
//--    3段式状态机(Mealy)
//==================================================================
 
//------------<模块及端口声明>----------------------------------------
module FSM_Mealy_3(
	input 		sys_clk		,			//输入系统时钟、50M
	input 		sys_rst_n	,   		//复位信号、低电平有效
	input 		money		,   		//投币输入,高电平有效
										
	output reg	cola            		//可乐输出,高电平有效
);
 
//------------<状态机参数定义>------------------------------------------
localparam	IDLE  = 3'b0001,
			ONE   = 3'b0010,
			TWO   = 3'b0100;
			
//------------<reg定义>-------------------------------------------------
reg	[3:0]	cur_state;					//定义现态寄存器
reg	[3:0]	next_state;					//定义次态寄存器
//-----------------------------------------------------------------------
//--状态机第一段:同步时序描述状态转移
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cur_state <= IDLE;				//复位初始状态
	else
		cur_state <= next_state;		//次态转移到现态
end
//-----------------------------------------------------------------------
//--状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
//-----------------------------------------------------------------------
always@(*)begin
	case(cur_state)						//组合逻辑
										//根据当前状态、输入进行状态转换判断										
		IDLE:begin				
			if(money)					
				next_state = ONE;		//投币1元,则状态转移到ONE
			else 
				next_state = IDLE;		//没有投币,则状态保持	
		end					
		ONE:begin				
			if(money)
				next_state = TWO;		//投币1元,则状态转移到TWO
			else 
				next_state = ONE;		//没有投币,则状态保持
		end
		TWO:begin				
			if(money)
				next_state = IDLE;		//投币1元,则状态转移到IDLE
			else                        
				next_state = TWO;       //没有投币,则状态保持
		end	
		default:begin					//默认状态同IDLE
			if(money)
				next_state = ONE;
			else 
				next_state = IDLE;	
		end
	endcase
end
//-----------------------------------------------------------------------
//--状态机第三段:时序逻辑描述输出
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cola <= 1'b0;					//复位、初始状态 
	else
		case(cur_state)					//根据当前状态进行输出
			IDLE:	cola <= 1'b0;		//无可乐输出(因为输入不管是0、1都是输出0,所以省略写法)			
			ONE:	cola <= 1'b0;		//无可乐输出(因为输入不管是0、1都是输出0,所以省略写法)	
			TWO:begin					
				if(money)
					cola <= 1'b1;		//如果输入1,则输出可乐
				else
					cola <= 1'b0;		//如果输入0,则无可乐输出
			end
			default:cola <= 1'b0;		//默认无可乐输出
		endcase
end
endmodule

Moore 状态机:组合逻辑的输出只取决于当前状态。
Moore型状态机第三段采用cur_state或next_state都可以,区别在于基于next_state输出是立刻变化的,基于cur_state输出会延迟一个周期
在这里插入图片描述

  • Mealy状态机比Moore状态机的状态个数要少;
  • Mealy状态机比Moore状态机的输出要早一个时钟周期
//==================================================================
//--    3段式状态机(Moore)
//==================================================================
 
//------------<模块及端口声明>----------------------------------------
module FSM_Moore_3(
	input 		sys_clk		,			//输入系统时钟、50M
	input 		sys_rst_n	,   		//复位信号、低电平有效
	input 		money		,   		//投币输入,高电平有效
										
	output reg	cola            		//可乐输出,高电平有效
);
 
//------------<状态机参数定义>------------------------------------------
localparam	IDLE  = 4'b0001,
			ONE   = 4'b0010,
			TWO   = 4'b0100,
			THREE = 4'b1000;
			
//------------<reg定义>-------------------------------------------------
reg	[3:0]	cur_state;					//定义现态寄存器
reg	[3:0]	next_state;					//定义次态寄存器
 
//-----------------------------------------------------------------------
//--状态机第一段:同步时序描述状态转移
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cur_state <= IDLE;				//复位初始状态
	else
		cur_state <= next_state;		//次态转移到现态
end
 
//-----------------------------------------------------------------------
//--状态机第二段:组合逻辑判断状态转移条件,描述状态转移规律以及输出
//-----------------------------------------------------------------------
always@(*)begin
	case(cur_state)						//组合逻辑
										//根据当前状态、输入进行状态转换判断										
		IDLE:begin				
			if(money)					
				next_state = ONE;		//投币1元,则状态转移到ONE
			else 
				next_state = IDLE;		//没有投币,则状态保持	
		end					
		ONE:begin				
			if(money)
				next_state = TWO;		//投币1元,则状态转移到TWO
			else 
				next_state = ONE;		//没有投币,则状态保持
		end
		TWO:begin				
			if(money)
				next_state = THREE;		//投币1元,则状态转移到THREE
			else                        
				next_state = TWO;       //没有投币,则状态保持
		end	
		THREE:begin				
			if(money)
				next_state = ONE;		//投币1元,则状态转移到ONE
			else                        
				next_state = IDLE;      //没有投币,则状态保持
		end
		default:begin					//默认状态同IDLE
			if(money)
				next_state = ONE;
			else 
				next_state = IDLE;	
		end
	endcase
end
 
//-----------------------------------------------------------------------
//--状态机第三段:时序逻辑描述输出
//-----------------------------------------------------------------------
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cola <= 1'b0;					//复位、初始状态 
	else
		case(next_state)					//根据当前状态进行输出
			IDLE:	cola <= 1'b0;		//无可乐输出			
			ONE:	cola <= 1'b0;		//无可乐输出
			TWO:	cola <= 1'b0;		//无可乐输出
			THREE:	cola <= 1'b1;		//输出可乐
			default:cola <= 1'b0;		//默认无可乐输出
		endcase
end
 
endmodule

七、偶数分频电路

计数翻转法:计数到 N/2-1,然后时钟翻转、计数器清零,如此循环就可以得到 N(偶)分频。

module divide_2 
( 
    input clk , // system clock 50Mhz on board
    input rst_n, // system rst, low active 
    output reg out_clk // output signal
);

parameter N = 4 ;

reg [N/2-1:0] cnt ;
 
 //===============================================================
 // ------------------------- MAIN CODE -------------------------
 //===============================================================
 
 always @ (posedge clk or negedge rst_n) begin
 if(!rst_n) begin
    cnt <= 0;
    out_clk <= 0;
 end
 else begin
    if(cnt==N/2-1) begin
        out_clk <= ~out_clk;
        cnt <= 0;
    end
 else
    cnt <= cnt + 1;
 end
 end
 endmodule

计数器法:利用计数器各位周期变换的特性进行分频。

module CNT 
  ( 
  input clk , // system clock 50Mhz on board
  input rst_n, // system rst, low active 
  output reg [2:0] y // output signal
  );
//y[0]二分频
//y{1}四分频
always @ (posedge clk or negedge rst_n) begin
   if (rst_n == 1'b0)
    y <= 3'b0 ;
   else
    y <= y + 1'b1 ;
   end
 
endmodule

八、奇数分频电路

设计思路:分别在时钟的上升沿和下降沿计数进行周期扩展,得到clk1、clk2。二者相位相差半个周期,相或即可得到占空比50%的奇数分频时钟。

module odd_div(
    input clk,
    input rstn,
    output out_clk
    );

parameter N = 5;

reg [N/2:0] cnt1;
reg [N/2:0] cnt2;

reg out_clk1;
reg out_clk2;
//周期扩展
always@(posedge clk or negedge rstn)begin
    if(!rstn)begin
        out_clk1<='d0;
        cnt1<=1;
    end
    else begin
        if(out_clk1==0)begin
            if(cnt1==N/2+1)begin
                cnt1<=1;
                out_clk1<=~out_clk1;
            end
            else begin
                cnt1<=cnt1+1'b1;
            end
        end
        else begin
            if(cnt1==N/2)begin
                cnt1<=1;
                out_clk1<=~out_clk1;
            end
            else begin
                cnt1<=cnt1+1'b1;
            end
        end
    end
end

always@(negedge clk or negedge rstn)begin
    if(!rstn)begin
        out_clk2<='d0;
        cnt2<=1;
    end
    else begin
        if(out_clk2==0)begin
            if(cnt2==N/2+1)begin
                cnt2<=1;
                out_clk2<=~out_clk2;
            end
            else begin
                cnt2<=cnt2+1'b1;
            end
        end
        else begin
            if(cnt2==N/2)begin
                cnt2<=1;
                out_clk2<=~out_clk2;
            end
            else begin
                cnt2<=cnt2+1'b1;
            end
        end
    end
end
//改变占空比
assign out_clk=out_clk1|out_clk2;
endmodule

在这里插入图片描述

九、RAM读写设计

半导体存储器包括随机存储器(RAM)和只读存储器(ROM),RAM包括静态RAM和动态RAM。

动态 RAM 包括 SDRAM,DDR SDRAM,DDR2 SDRAM,DDR3 SDRAM 以及 DDR4 SDRAM 等。

静态RAM一般包括单端口RAM、伪双口RAM、真双口RAM。

ROM包括PROM、EPROM、EEPROM等。

在这里插入图片描述

FIFO和RAM的区别:
结构:FIFO是先入先出,没有地址线,不能对存储单元寻址;RAM端口都有地址线,可以对存储单元寻址。
应用:FIFO 一般放在传输带宽不一致的地方,用来吸收流量突发;RAM一般用在需 要根据地址进行写或者读的地方,存储一些信息。

单端口RAM

单端口RAM:只有一个读写口,读写都是通过该口访问RAM。

总使能信号ENA:ENA 为 1 且 WEA 为 1 表示写有效,ENA 为 1 且 WEA 为 0 表示读有效

在这里插入图片描述

//单端口RAM结构
module sp_ram(
    input               clk ,
    input               en  ,
    input               wen ,
    input       [7:0]   din ,
    input       [4:0]   addr,
    output reg  [7:0]    dout
    );

reg [7:0] ram [31:0]; 
//写
always@(posedge clk)begin
    if(en && wen)begin
        ram[addr]<=din;
    end
end
//读
always@(posedge clk)begin
    if(en && !wen)begin
        dout<=ram[addr];
    end
    else begin
        dout<=8'hx;
    end
end
endmodule

//单端口RAM读写
module sp_ram_rw(
    input clk,
    input rstn   
    );

wire en;
wire wren;
wire rden;
wire [7:0] ram_rd_data;
reg [4:0] ram_addr;
reg [7:0] ram_wr_data;
reg [5:0] rw_cnt;

//RAM使能信号
assign wren=(rw_cnt>=0 && rw_cnt<=31) ? 1'b1:1'b0;
assign rden=(rw_cnt>=32 && rw_cnt<=63) ? 1'b1:1'b0;

assign en= wren | rden;

//读写控制计数
always@(posedge clk or negedge rstn)begin
    if(!rstn)begin
        rw_cnt<='d0;
    end
    else if(rw_cnt==6'd63)begin
         rw_cnt<='d0;          
    end
    else begin
        rw_cnt<=rw_cnt+1'b1;
    end
end
//RAM地址信号
always@(posedge clk or negedge rstn)begin
    if(!rstn)begin
        ram_addr<='d0;
    end
    else if(ram_addr == 5'd31)begin
        ram_addr<='d0;
    end
    else begin
        ram_addr<=ram_addr+1'b1;
    end
end
//RAM数据信号
always@(posedge clk or negedge rstn)begin
    if(!rstn)begin
        ram_wr_data<='d0;
    end
    else if(rw_cnt>=0 && rw_cnt<=31)begin
        ram_wr_data<=ram_wr_data+1'b1;
    end
    else begin
        ram_wr_data<=8'd0;
    end
end
sp_ram sp_ram_u(
    . clk (clk),
    . en  (en),
    . wen (wren),
    . din (ram_wr_data),
    . addr(ram_addr),
    . dout(ram_rd_data)
    );
endmodule

伪双口RAM

伪双口RAM:一个端口只能读,一个端口只能写,读写可以同时访问。
在这里插入图片描述
读写同时有效且读写同一地址时,会产生读写冲突,此时很可能读出的数据是无效的。

冲突处理:判断冲突,然后将写数据寄存1拍赋值给读数据

always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0)
        conflict <= 1'b0 ;
    else if ( wen && ren && (waddr == raddr ))
        conflict <= 1'b1 ;
    else
        conflict <= 1'b0 ;
    end
     
assign dout = conflict ? din_dly1 : q ;
//伪双口RAM结构
module tp_ram ( 
  input clocka , //ram clk 
  input clockb , //ram clk 
  input wren , //ram 写使能 
  input rden , //ram 读使能 
  input [4:0] wr_address , //ram 写地址 
  input [4:0] rd_address , //ram 写地址 
  input [7:0] data , //ram 写数据 
  
   output reg [7:0] q //ram 读数据 
   ); 
   
   //reg define 
   
   reg [7:0] ram [31:0] ; //ram 数据 
   
   //***************************************************** 
   //** main code 
   //***************************************************** 
   
   always @(posedge clocka ) begin 
   if(wren)  

    ram[wr_address] <= data; 
   end 
   
   always @(posedge clockb ) begin 
   if(rden) 
    q <= ram[rd_address]; 
   else 
    q <= 8'hx ; 
   end 
   
   endmodule
//伪双口RAM读写
module tp_ram_rw( 
	input clk , //时钟信号 
	input rst_n //复位信号,低电平有效 
); 

//wire define 
wire ram_wr_en ; //ram 写使能 
wire ram_rd_en ; //ram 读使能 
wire [7:0] ram_rd_data ; //ram 读数据 
 
 wire [4:0] ram_waddr ; //ram 写地址 
 wire [4:0] ram_raddr ; //ram 读地址 
 
 //reg define 
 reg [5:0] rw_cnt ; //读写控制计数器 
 
 
 reg [7:0] ram_wr_data; //ram 写数据 
 
 //***************************************************** 
 //** main code 
 //***************************************************** 
 
 //rw_cnt 计数范围在 0~31,ram_wr_en 为高电平;32~63 时,ram_wr_en 为低电平 
 assign ram_wr_en = ((rw_cnt >= 6'd0) && (rw_cnt <= 6'd31)) ? 1'b1 : 1'b0; 
 //rw_cnt 计数范围在 1~32,ram_rd_en 为高电平;其他值时,ram_rd_en 为低电平 
 assign ram_rd_en = ((rw_cnt >= 6'd1) && (rw_cnt <= 6'd32)) ? 1'b1 : 1'b0; 
 
 //读写控制计数器,计数器范围 0~63 
 always @(posedge clk or negedge rst_n) begin 
 	if(rst_n == 1'b0) 
		 rw_cnt <= 6'd0; 
 	else if(rw_cnt == 6'd63) 
 		rw_cnt <= 6'd0; 
	 else 
 		rw_cnt <= rw_cnt + 6'd1; 
	 end 
 
 //读写地址产生 
 assign ram_waddr = rw_cnt[4:0] ; 
 assign ram_raddr = rw_cnt[4:0] - 5'd1 ;  


tp_ram u_tp_ram ( 
.wr_address (ram_waddr), 
.rd_address (ram_raddr), 
.clocka (clk ), 
.clockb (clk ), 
.data (ram_wr_data), 
.rden (ram_rd_en), 
.wren (ram_wr_en), 
.q (ram_rd_data) 
); 

endmodule 

真双口RAM

真双口RAM:有两个独立的读写口,每个端口都可以独立地发起读或者写。
在这里插入图片描述
读写冲突处理:

  1. 允许两个端口同时读;
  2. 两个端口读写同一地址时,把最新的写数据寄存1拍赋值给读数据;
  3. 两个端口向同一地址写时,把两个写端口的数据经处理后通过一个写端口写入,另一个写端口关断处理;
//真双口RAM结构
module dp_ram(
    input               clocka      ,
    input               clockb      ,
    input               wren_a      ,
    input               rden_a      ,
    input               wren_b      ,
    input               rden_b      ,
    input       [4:0]   address_a   ,
    input       [4:0]   address_b   ,
    input       [7:0]   data_a      ,
    input       [7:0]   data_b      ,
    output reg [7:0]    q_a         ,
    output reg [7:0]    q_b
    );
reg [7:0] ram [31:0] ; //ram 数据

always@(posedge clocka)begin
    if(wren_a)
        ram[address_a]<=data_a;
    if(wren_b)
        ram[address_b]<=data_b;
end

always@(posedge clocka)begin
    if(rden_a)begin
        q_a<=ram[address_a];
    end
    else begin
        q_a<=8'hx;
    end
end

always@(posedge clocka)begin
    if(rden_b)begin
        q_b<=ram[address_b];
    end
    else begin
        q_b<=8'hx;
    end
end

endmodule

//真双口RAM读写
module dp_ram_rw(
    input clk,
    input rst_n
    );
    
wire ram_wr_en ; //ram 写使能 
wire ram_rd_en ; //ram 读使能 
wire [7:0] ram_rd_data_a ; //ram 读数据 
wire [7:0] ram_rd_data_b ; //ram 读数据 

wire [4:0] ram_waddr ; //ram 写地址 
wire [4:0] ram_raddr ; //ram 读地址 
wire [7:0] ram_wr_data; //ram 写数据 

wire [4:0] address_a ; //ram 地址 a 
wire [4:0] address_b ; //ram 地址 b 

wire rden_a ; //ram 读使能 
wire rden_b ; //ram 读使能 

wire wren_a ; //ram 写使能 
wire wren_b ; //ram 写使能 

wire [7:0] data_a ; //ram 写数据 
wire [7:0] data_b ; //ram 写数据 

//reg define 
reg [5:0] rw_cnt ; //读写控制计数器 

reg [4:0] ram_addr ; //ram 读写地址 
reg flag ; //读写切换 flag

//rw_cnt 计数范围在 0~31,ram_wr_en 为高电平;32~63 时,ram_wr_en 为低电平 
assign ram_wr_en = ((rw_cnt >= 6'd0) && (rw_cnt <= 6'd31)) ? 1'b1 : 1'b0; 
//rw_cnt 计数范围在 1~32,ram_rd_en 为高电平;其他值时,ram_rd_en 为低电平 
assign ram_rd_en = ((rw_cnt >= 6'd1) && (rw_cnt <= 6'd32)) ? 1'b1 : 1'b0; 

//写数据产生 
assign ram_wr_data = rw_cnt[4:0] ; 

//读写地址产生 
assign ram_waddr = rw_cnt[4:0] ; 
assign ram_raddr = rw_cnt[4:0] - 5'd1 ; 

// A 端口的控制 
assign address_a = flag ? ram_waddr : ram_raddr ; 
assign data_a = flag ? ram_wr_data : 8'd0 ; 
assign rden_a = flag ? 1'b0 : ram_rd_en ; 
assign wren_a = flag ? ram_wr_en : 1'b0 ; 

// B 端口的控制 
assign address_b = flag ? ram_raddr : ram_waddr ; 
assign data_b = flag ? 8'd0 : ram_wr_data ; 
assign rden_b = flag ? ram_rd_en : 1'b0 ; 
assign wren_b = flag ? 1'b0 : ram_wr_en ; 
//读写控制计数
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
       rw_cnt<='d0; 
    end
    else if(rw_cnt==63)begin
        rw_cnt<='d0;
    end
    else begin
        rw_cnt<=rw_cnt+1'b1;
    end
end
//端口读写切换
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        flag<=1'd0;
    end
    else if(rw_cnt==63)begin
        flag<=~flag;
    end
end

dp_ram dp_ram_u(
    .clocka     (clk) ,
    .clockb     (clk) ,
    .wren_a     (wren_a) ,
    .rden_a     (rden_a) ,
    .wren_b     (wren_b) ,
    .rden_b     (rden_b) ,
    .address_a  (address_a) ,
    .address_b  (address_b) ,
    .data_a     (data_a) ,
    .data_b     (data_b) ,
    .q_a        (ram_rd_data_a) ,
    .q_b        (ram_rd_data_b)
    );
endmodule

十、FIFO

同步FIFO
异步FIFO

十一、异步电路设计

跨时钟域处理

十二、位宽转换电路

整数倍位宽转换

窄到宽

设计思路:根据输入和输出位宽的比值对输入数据的有效信号进行计数,然后得到输出数据的有效信号和输出数据。

module width_change_8to32(
    input clk,
    input rst_n,
    input [7:0] a,
    input a_vld,
    output reg [31:0] b,
    output reg b_vld
    );
    
reg [2:0] vld_cnt;
reg [7:0] a_r [2:0];
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        vld_cnt<='d0;
    end
    else if(a_vld)begin
        if(vld_cnt==3'd3)begin
            vld_cnt<=3'd0;
        end
        else begin
            vld_cnt<=vld_cnt+1'b1;
        end
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        b_vld<='d0;
    end
    else if(a_vld && vld_cnt==3'd3)begin
        b_vld<=1'b1;
    end
    else begin
        b_vld<=1'b0;
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        a_r[0]<='d0;
        a_r[1]<='d0;
        a_r[2]<='d0;
    end
    else if(a_vld)begin
        a_r[0]<=a;
        a_r[1]<=a_r[0];
        a_r[2]<=a_r[1];       
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        b<='d0;
    end
    else if(a_vld && vld_cnt==3'd3)begin
        b<={a_r[2],a_r[1],a_r[0],a};
    end
end
endmodule

在这里插入图片描述

宽到窄

设计思路:将输入数据的各段寄存,然后用计数器控制顺序输出。

module width_change_32to8(
    input clk,
    input rst_n,
    input [31:0] a,
    input a_vld,
    output reg [7:0] b,
    output reg b_vld
    );

reg [7:0] b_tmp[3:0];  
reg [2:0] vld_cnt;


always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        b_tmp[0]<='d0;
        b_tmp[1]<='d0;
        b_tmp[2]<='d0;
        b_tmp[3]<='d0;
    end
    else if(a_vld)begin
        b_tmp[0]<=a[31:24];
        b_tmp[1]<=a[23:16];
        b_tmp[2]<=a[15:8];
        b_tmp[3]<=a[7:0];
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        vld_cnt<='d0;
    end
    else if(a_vld)begin
        if(vld_cnt==3'd4)begin
            vld_cnt<='d0;
        end
        else begin
            vld_cnt<=vld_cnt+1'b1;
        end
    end
end
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        b_vld<='d0;
    end
    else begin
        b_vld<=(vld_cnt>0)?1'b1:1'b0;
    end
    
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        b<='d0;
    end
    else begin
        case(vld_cnt)
            3'd1:begin
                b<=b_tmp[0];
            end           
            3'd2:begin
                b<=b_tmp[1];
            end
            3'd3:begin
                b<=b_tmp[2];
            end
            3'd4:begin
                b<=b_tmp[3];
            end
            default:
                b<=b;
        endcase
    end
end
endmodule

在这里插入图片描述

非整数倍位宽转换

窄到宽

设计思路:根据输入和输出位宽的比值对输入的有效信号计数,该比值决定了何时输出数据。

module width_change_8to20(
    input clk,
    input rst_n,
    input [7:0] a,
    input a_vld,
    output reg [19:0] b,
    output reg b_vld
    );

reg [7:0] a_lock;
reg [7:0] a_lock2;
reg [2:0] vld_cnt;

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        a_lock<='d0;
        a_lock2<='d0;
    end
    else if(a_vld) begin
        a_lock<=a;
        a_lock2<=a_lock;
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        vld_cnt<='d0;
    end
    else if(a_vld) begin
        if(vld_cnt == 3'd4)begin
            vld_cnt<='d0;
        end
        else begin
            vld_cnt<=vld_cnt+1'b1;
        end       
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        b_vld<='d0;
    end
    else if(a_vld && vld_cnt == 3'd2 ) begin
        b_vld<='d1;
    end  
    else if(a_vld && vld_cnt == 3'd4)begin
        b_vld<='d1;
    end  
    else begin
        b_vld<='d0;
    end
end

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        b<='d0;
    end
    else if(a_vld && vld_cnt == 3'd2)begin
        b<={a_lock2,a_lock,a[7:4]};
    end
    else if(a_vld && vld_cnt == 3'd4)begin
        b<={a_lock2[3:0],a_lock,a};
    end   
end
endmodule

在这里插入图片描述

十三、调度器

调度器:用于在多个队列出队时选择哪个队列先出。

优先级调度器

SP调度:严格按照优先级从高到低的次序优先发送较高优先级队列中的报文,当较高优先级队列为空时,再发送较低优先级队列中的报文。

module sp_sch(
    input clk,
    input rst_n,
    input q0_rdy,
    input q1_rdy,
    input q2_rdy,
    output [2:0] sel
    );

assign sel=q2_rdy ? 3'b100 :(q1_rdy ? 3'b010 : 3'b001);

endmodule

轮询调度器

RR调度器:总是顺序地移到下一个有包要发送的队列(空队列被跳过)。

module RR_sch(
    input clk,
    input rst_n,
    input q0_rdy,
    input q1_rdy,
    input q2_rdy,
    output [2:0] sel
    );
    
wire rr_vld;

reg [2:0] last_winner;
reg [2:0] cur_winner;

assign rr_vld=q0_rdy | q1_rdy | q2_rdy;

always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
       last_winner<='d0;
       cur_winner<='d0; 
    end 
    else if(rr_vld)begin
        last_winner<=cur_winner;
    end
end

always@(*)begin
    if(last_winner == 3'b001)begin
        if(q1_rdy == 1'b1)
            cur_winner<=3'b010;
        else if(q2_rdy == 1'b1)
            cur_winner<=3'b100;
        else if(q0_rdy == 1'b1)
            cur_winner<=3'b001;
        else 
            cur_winner<=3'b000;
    end
    else if(last_winner == 3'b010)begin
        if(q2_rdy == 1'b1)
            cur_winner<=3'b100;
        else if(q0_rdy == 1'b1)
            cur_winner<=3'b001;
        else if(q1_rdy == 1'b1)
            cur_winner<=3'b010;
        else 
            cur_winner<=3'b000;
    end
    else if(last_winner == 3'b100)begin
        if(q0_rdy == 1'b1)
            cur_winner<=3'b001;
        else if(q1_rdy == 1'b1)
            cur_winner<=3'b010;
        else if(q2_rdy == 1'b1)
            cur_winner<=3'b100;
        else 
            cur_winner<=3'b000;
    end
    else begin
        if(q0_rdy == 1'b1)
            cur_winner<=3'b001;
        else if(q1_rdy == 1'b1)
            cur_winner<=3'b010;
        else if(q2_rdy == 1'b1)
            cur_winner<=3'b100;
        else 
            cur_winner<=3'b000;
    end
end

assign sel=cur_winner;

endmodule

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

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

相关文章

C++---基础概念

1 命名空间 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存 在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化&#xff0c; 以避免命名冲突或名字污染&#xff0c;n…

Redis - 缓存

文章目录 目录 文章目录 1. 什么是缓存&#xff1f; 2. 使用Redis作为缓存 2.1 关系型数据库的缺点 3. 缓存的更新策略 3.1 定期生成 3.2 实时生成 缓存淘汰策略 4. 缓存预热, 缓存穿透, 缓存雪崩 和 缓存击穿 缓存预热 缓存穿透 缓存雪崩 缓存击穿 总结 1. 什么…

Web安全之XSS跨站脚本攻击:如何预防及解决

1. 什么是XSS注入 XSS&#xff08;跨站脚本攻击&#xff0c;Cross-Site Scripting&#xff09;是一种常见的Web安全漏洞&#xff0c;通过注入恶意代码&#xff08;通常是JavaScript&#xff09;到目标网站的网页中&#xff0c;以此在用户浏览网页时执行。攻击者可以通过XSS获取…

特征值分解(EVD)和奇异值分解(SVD)—应用于图片压缩

特征值分解(EVD)和奇异值分解(SVD)—应用于图片压缩 目录 前言 一、特征值分解 二、应用特征值分解对图片进行压缩 三、矩阵的奇异值分解 四、应用奇异值分解对图片进行压缩 五、MATLAB仿真代码 前言 学习了特征值分解和奇异值分解相关知识&#xff0c;发现其可以用于图片…

初次使用住宅代理有哪些常见误区?

随着网络技术的发展&#xff0c;住宅代理因其高匿名性和稳定性成为许多用户进行网络活动的首选工具。然而&#xff0c;对于新手而言&#xff0c;使用住宅代理时往往容易陷入一些误区&#xff0c;这不仅可能影响使用效果&#xff0c;还可能带来安全风险。本文将探讨新手在使用住…

我与Linux的爱恋:yum和vim以及gcc的使用

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;Linux的学习 文章目录 ​1.Linux软件包管理器yum2.Linux开发工具3.Linux编译器 vimvim的基本概念vim的基本操作vim正常模式命令集vim末行模式命令集vim操作总结批量化注释批量化去注释简…

【数据库中级】1_DBeaver操作数据库

文章目录 一、连接数据库1.1 命令行连接数据库1.2 DBeaver工具连接数据库 二、DBeaver操作数据库2.1 通过DBeaver操作数据库2.2 通过DBeaver操作表2.3 通过DBeaver操作数据 三、DBeaver界面3.1 SQL编辑区3.2 导航区3.3 修改字体大小 一、连接数据库 1.1 命令行连接数据库 命令…

《Learning to Count without Annotations》CVPR2024

摘要 论文提出了一种名为UnCounTR的模型&#xff0c;该模型能够在没有任何手动标注的情况下学习进行基于参考的对象计数。这是通过构建“Self-Collages”&#xff08;自我拼贴画&#xff09;实现的&#xff0c;即在背景图像上粘贴不同对象的图像作为训练样本&#xff0c;提供覆…

【Git 学习笔记_24】Git 实用冷门操作技巧(四)—— 更多实用 git 别名设置、交互式新增提交

文章目录 11.8 更多别名设置别名1&#xff1a;只查看当前分支&#xff08;git b&#xff09;别名2&#xff1a;以图表形式显示自定义格式的 git 日志&#xff08;git graph&#xff09;别名3&#xff1a;查看由于合并分支导致的冲突后仍有冲突的、待合并的文件列表&#xff08;…

Excel文档的读取(1)

熟悉使用Excel的同学应该都知道&#xff0c;在单个Excel表格里想要分商品计算总销售额&#xff0c;使用数据透视表也可以非常快速方便的获得结果。但当有非常大量的Excel文件需要处理时&#xff0c;每一个Excel文件单独去做数据透视也会消耗大量的时间。就算使用Power Query这样…

python容器3——字典

&#xff08;1&#xff09; 什么是字典 字典&#xff1a;python中使用关键字dict表示 字典中允许通过key:value键值对的方式存储数据&#xff0c;让数据的管理更加友好&#xff01; 如图&#xff1a; 字典是一个哈希结构 (传入一个值算出内存地址&#xff0c;将该值保存在该…

产品经理就业

供需关系 1.需求分析核心价值是? 将真实的用户需求分析得到与之匹配的产品方案(功能) 2.Y模型的主要内容及其侧重点? 1)用户需求、2)目标动机、3)产品功能、4)人性(马斯洛需求) 1-2-4侧重深入想清楚需求本质 Why、4 -2-3 侧重浅出 How 结果输出 3.可以从哪些角度做好需求分析…

java.lang.IndexOutOfBoundsException: setSpan ( 0...x ) ends beyond length X

1&#xff0c;可能是EditText&#xff0c;setSelection(x)时超过了 输入框内容的实际长度导致的。 2&#xff0c;手机开启“拼写检查功能”&#xff0c;EditText设置了最大长度&#xff0c;选择提示的某一项文案时超过设置的最大长度限制&#xff0c;导致崩溃。 针对情况2 开…

【电子通识】洁净度等级划分及等级标准

洁净度常用于评估半导体、生物制药、医疗、实验室及科研院所、新能源等领域的洁净室、无尘室或者无菌室等环境。 一般来说&#xff0c;晶圆光刻、制造、测试等级为100级或1000级的洁净间&#xff0c;百级洁净间要求空气中0.5微米的尘埃粒子数不得超过每立方米3520个&#xff1b…

移动UI:新手指引页面,跟着指引不迷路。

移动端新手指引在提供用户引导、提升用户体验、提高用户留存率、促进功能使用和降低用户流失率方面都有积极的作用。 移动端新手指引在应用程序或移动网站中有以下几个作用&#xff1a; 1. 提供用户引导&#xff1a; 新手指引可以帮助用户快速了解应用程序或移动网站的功能和…

【网络安全】Exif 数据储存型XSS

未经许可,不得转载。 文章目录 Exif步骤Exif EXIF(Exchangeable Image File Format)数据是一种存储在图像文件中的元数据格式,常用于数码照片和扫描图像。它包含了与图像相关的各种信息,比如拍摄日期和时间、相机品牌和型号、拍摄时的设置(如曝光时间、光圈、ISO等)、地…

输送线相机拍照信号触发(博途PLC高速计数器中断立即输出应用)

博途PLC相关中断应用请参考下面文章链接: T法测速功能块 T法测速功能块(博途PLC上升沿中断应用)-CSDN博客文章浏览阅读165次。本文介绍了博途PLC中T法测速的原理和应用,包括如何开启上升沿中断、配置中断以及T法测速功能块的使用。重点讲述了在中断事件发生后执行的功能块处…

dp算法练习【6】

最长公共子序列 1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序…

被审稿人批得体无完肤?参考文献这样引用就对了!

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 审稿人对参考文献引用提出质疑&#xff0c;在comments中还挺常见的。一般来说&#xff0c;是最新的、相关的、重要的文献引用缺失。此外&#xff0c;如果仔细分析引文来源&…

QT定时器QObiect/QTimer

QT定时器 一、QObiect: startTimer ----------- killTimer 电子相册&#xff0c;利用定时器轮播图片 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);picID …