通用读写仲裁模块(FPGA实现)

news2024/11/29 6:35:55

  当涉及多个模块向同一个模块进行读写操作、向一个半双工模块请求读写,甚至综合一下,多个模块向一个半双工模块发起读写请求,那就要涉及读写仲裁。因为最近做的项目中涉及的读写仲裁太多了,所以就想还是要写一个通用的读写仲裁模块,最好还是具备“凡请求,必执行”的功能的(因为一般简单实现的仲裁在发生冲突时,会选择执行一个,而直接忽视其他请求,这就对发起读写请求的模块的控制逻辑造成了不必要的麻烦),于是就有了这篇文章。

  由于每个人实现的模块控制信号不尽相同,因此本文档中的代码仅作为一种实现思路的参考。下面以写仲裁作为例子介绍实现思路,读仲裁逻辑与之相同。

  首先看怎么实现“凡请求,必执行”功能的,我们知道,若想将某些位进行置位,可以使用或运算,因此

SW_ARB: begin
    wr_busy		<= wr_busy | wr_req;		//将出现请求的通道标记
end

就可以将出现了写请求的通道标记,之后轮询时如果发现通道具有标记,则进入写功能流程。发现通道具有标记的代码如下

if(|(wr_busy & W_CH_SEL)) begin		//检测到该通道存在请求,启动写进程
    next_state_W	<= SW_WR;
end
else begin
    next_state_W	<= SW_POLL;		//否则轮询下个通道
end

首先将 wr_busy 和 W_CH_SEL 做与运算,则若当前通道存在标记,对应位将为 1,而若不存在标记,对应位为 0,其他非当前检查通道的位都为 0,之后再对与运算后的结果做一个或运算,就得到当前通道是否存在标记的判断值了。

  在进行完写操作后,需要将对应通道的标记清除,而我们也知道想要实现复位操作,可以使用与运算,因此

SW_END: begin
	wr_busy		<= wr_busy & (~W_CH_SEL);	//清除该通道的标记
end

就可以把对应通道的标记清除,以示写操作完成,而对应通道就可以决定是否再发起写请求了。

  轮询的实现,使用 CHANNEL_NUM 宽度的信号 W_CH_SEL 进行通道轮询,初始值置为 0b1,若检测到当前通道不存在请求标记,则轮询下一通道,实现方式为循环移位

SW_POLL: begin
	W_CH_SEL	<= {W_CH_SEL[CHANNEL_NUM-2:0], W_CH_SEL[CHANNEL_NUM-1]};	//检查下一个通道
end

  为了实现全双工时,读写过程的并发,因此读仲裁、写仲裁的状态机应该是独立的,分别维护自身的状态 state_W/state_R,而在半双工模式下,读写通道不能同时进入执行状态,因此需要判断对方的状态,且为了避免读写通道同时处于裁决状态时一起进入读写流程的问题,state_W 应当在检测到 state_R 处在轮询状态时才能进行裁决,对应的状态控制如下

SW_ARB: begin
    if(is_FULL_DUPLEX | (state_R == SR_POLL)) begin	//全双工,或者半双工且读通道正在通道轮询
        if(|(wr_busy & W_CH_SEL)) begin					//判断是否存在标记
            next_state_W	<= SW_WR;						//有标记,进入写进程
        end
        else begin
            next_state_W	<= SW_POLL;						//否则轮询
        end
    end
    else begin
        next_state_W	<= SW_ARB;					//半双工,且读通道正在裁决或执行读操作,则等待
    end
end

代码

/* 
 * file			: arb.v
 * author		: 今朝无言
 * date			: 2023-05-31
 * version		: v1.0
 * description	: 通用读写仲裁模块
 */
module arb(
input										clk,
input										rst_n,

//写通道仲裁
input		[CHANNEL_NUM-1:0]				wr_req,		//CHANNEL_NUM路写通道请求,高电平有效
input		[CHANNEL_NUM*DATA_WIDTH-1:0]	wrdata,		//对应的写数据
input		[CHANNEL_NUM*ADDR_WIDTH-1:0]	wr_addr,	//对应的写地址
output	reg	[CHANNEL_NUM-1:0]				wr_busy,	//回应各个通道是否写忙碌

output	reg									wr_req_o,	//输出到实际写入模块的写请求信号
output	reg	[DATA_WIDTH-1:0]				wrdata_o,	//对应的写数据
output	reg	[ADDR_WIDTH-1:0]				wr_addr_o,	//对应的写地址
input										wr_busy_i,	//模块是否忙碌

//读通道仲裁
input		[CHANNEL_NUM-1:0]				rd_req,		//多路读请求,高电平有效
output	reg	[CHANNEL_NUM*DATA_WIDTH-1:0]	rddata,		//对应的多路读数据
input		[CHANNEL_NUM*ADDR_WIDTH-1:0]	rd_addr,	//对应的读地址
output	reg	[CHANNEL_NUM-1:0]				rd_busy,	//回应各个通道是否读忙碌

output	reg									rd_req_o,	//输出到实际读模块的读请求信号
input		[DATA_WIDTH-1:0]				rddata_i,	//获取的数据
output	reg	[ADDR_WIDTH-1:0]				rd_addr_o,	//对应的读地址
input										rd_busy_i	//模块是否忙碌
);

parameter	is_FULL_DUPLEX 	= 1;	//是否全双工
parameter	CHANNEL_NUM		= 2;	//仲裁通道数
parameter	DATA_WIDTH		= 8;	//数据位宽
parameter	ADDR_WIDTH		= 8;	//地址位宽

//------------------------Write Arbitrate--------------------------------
parameter	SW_IDLE		= 8'h01;
parameter	SW_ARB		= 8'h02;	//仲裁
parameter	SW_POLL		= 8'h04;	//轮询
parameter	SW_WR		= 8'h08;
parameter	SW_WITE		= 8'h10;
parameter	SW_END		= 8'h20;

reg		[7:0]	state_W			= SW_IDLE;
reg		[7:0]	next_state_W;

reg		[CHANNEL_NUM-1:0]	W_CH_SEL	= 1'b1;	//选择哪个通道

always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		state_W		<= SW_IDLE;
	end
	else begin
		state_W		<= next_state_W;
	end
end

always @(*) begin
	case(state_W)
	SW_IDLE: begin
		next_state_W		<= SW_ARB;
	end
	SW_ARB: begin
		if(is_FULL_DUPLEX | (state_R == SR_POLL)) begin
			if(|(wr_busy & W_CH_SEL)) begin		//检测到该通道存在请求,启动写进程(wrbusy中记录了哪些通道出现了写请求,但还没有处理)
				next_state_W	<= SW_WR;
			end
			else begin
				next_state_W	<= SW_POLL;		//否则轮询下个通道
			end
		end
		else begin
			next_state_W	<= SW_ARB;
		end
	end
	SW_POLL: begin
		next_state_W		<= SW_ARB;
	end
	SW_WR: begin
		if(wr_busy_i) begin
			next_state_W	<= SW_WITE;
		end
		else begin
			next_state_W	<= SW_WR;
		end
	end
	SW_WITE: begin
		if(~wr_busy_i) begin
			next_state_W	<= SW_END;
		end
		else begin
			next_state_W	<= SW_WITE;
		end
	end
	SW_END: begin
		next_state_W		<= SW_IDLE;
	end
	default: begin
		next_state_W		<= SW_IDLE;
	end
	endcase
end

integer		ch_index_W;
integer		i;
always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		wr_req_o	<= 1'b0;
		wrdata_o	<= 0;
		wr_addr_o	<= 0;
		wr_busy		<= 0;
		W_CH_SEL	<= 1'b1;
	end
	else begin
		ch_index_W	= 0;
		for(i=0; i<CHANNEL_NUM; i=i+1) begin
			if(W_CH_SEL[i]) begin
				ch_index_W	= i;
			end
		end

		case(state_W)
		SW_IDLE: begin
			wr_req_o	<= 1'b0;
			wrdata_o	<= 0;
			wr_addr_o	<= 0;
			wr_busy		<= wr_busy;
			W_CH_SEL	<= W_CH_SEL;
		end
		SW_ARB: begin
			wr_busy		<= wr_busy | wr_req;		//将出现请求的通道标记
		end
		SW_POLL: begin
			W_CH_SEL	<= {W_CH_SEL[CHANNEL_NUM-2:0], W_CH_SEL[CHANNEL_NUM-1]};	//检查下一个通道
		end
		SW_WR: begin
			wr_req_o	<= 1'b1;
			wrdata_o	<= wrdata[ch_index_W*DATA_WIDTH +: DATA_WIDTH];
			wr_addr_o	<= wr_addr[ch_index_W*ADDR_WIDTH +: ADDR_WIDTH];
		end
		SW_WITE: begin
			wr_req_o	<= 1'b0;
		end
		SW_END: begin
			wr_busy		<= wr_busy & (~W_CH_SEL);	//清除该通道的标记
		end
		default: begin
			wr_req_o	<= 1'b0;
			wrdata_o	<= 0;
			wr_addr_o	<= 0;
			wr_busy		<= wr_busy;
			W_CH_SEL	<= W_CH_SEL;
		end
		endcase
	end
end

//------------------------Read Arbitrate---------------------------------
parameter	SR_IDLE		= 8'h01;
parameter	SR_ARB		= 8'h02;	//仲裁
parameter	SR_POLL		= 8'h04;	//轮询
parameter	SR_RD		= 8'h08;
parameter	SR_WITE		= 8'h10;
parameter	SR_END		= 8'h20;

reg		[7:0]	state_R			= SR_IDLE;
reg		[7:0]	next_state_R;

reg		[CHANNEL_NUM-1:0]	R_CH_SEL	= 1'b1;	//选择哪个通道

always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		state_R		<= SR_IDLE;
	end
	else begin
		state_R		<= next_state_R;
	end
end

always @(*) begin
	case(state_R)
	SR_IDLE: begin
		next_state_R		<= SR_ARB;
	end
	SR_ARB: begin
		if(is_FULL_DUPLEX | (state_W == SW_POLL)) begin
			if(|(rd_busy & R_CH_SEL)) begin		//检测到该通道存在请求,启动读进程(rd_busy中记录了哪些通道出现了读请求,但还没有处理)
				next_state_R	<= SR_RD;
			end
			else begin
				next_state_R	<= SR_POLL;		//否则轮询下个通道
			end
		end
		else begin
			next_state_R	<= SR_POLL;
		end
	end
	SR_POLL: begin
		next_state_R		<= SR_ARB;
	end
	SR_RD: begin
		if(rd_busy_i) begin
			next_state_R	<= SR_WITE;
		end
		else begin
			next_state_R	<= SR_RD;
		end
	end
	SR_WITE: begin
		if(~rd_busy_i) begin
			next_state_R	<= SR_END;
		end
		else begin
			next_state_R	<= SR_WITE;
		end
	end
	SR_END: begin
		next_state_R		<= SR_IDLE;
	end
	default: begin
		next_state_R		<= SR_IDLE;
	end
	endcase
end

integer		ch_index_R;
integer		j;
always @(posedge clk or negedge rst_n) begin
	if(~rst_n) begin
		rd_req_o	<= 1'b0;
		rd_addr_o	<= 0;
		rddata		<= 0;
		rd_busy		<= 0;
		R_CH_SEL	<= 1'b1;
	end
	else begin
		ch_index_R	= 0;
		for(j=0; j<CHANNEL_NUM; j=j+1) begin
			if(R_CH_SEL[j]) begin
				ch_index_R	= j;
			end
		end

		case(state_R)
		SR_IDLE: begin
			rd_req_o	<= 1'b0;
			rd_addr_o	<= 0;
			rddata		<= rddata;
			rd_busy		<= rd_busy;
			R_CH_SEL	<= R_CH_SEL;
		end
		SR_ARB: begin
			rd_busy		<= rd_busy | rd_req;		//将出现请求的通道标记
		end
		SR_POLL: begin
			R_CH_SEL	<= {R_CH_SEL[CHANNEL_NUM-2:0], R_CH_SEL[CHANNEL_NUM-1]};	//检查下一个通道
		end
		SR_RD: begin
			rd_req_o	<= 1'b1;
			rd_addr_o	<= rd_addr[ch_index_R*ADDR_WIDTH +: ADDR_WIDTH];
		end
		SR_WITE: begin
			rd_req_o	<= 1'b0;
		end
		SR_END: begin
			rddata[ch_index_R*ADDR_WIDTH +: ADDR_WIDTH]		<= rddata_i;
			rd_busy		<= rd_busy & (~R_CH_SEL);	//清除该通道的标记
		end
		default: begin
			rd_req_o	<= 1'b0;
			rd_addr_o	<= 0;
			rddata		<= rddata;
			rd_busy		<= rd_busy;
			R_CH_SEL	<= R_CH_SEL;
		end
		endcase
	end
end

endmodule

测试代码 & 测试结果

`timescale 1ns/100ps

module arb_tb();

reg		clk_100M	= 1'b1;
always #5 begin
	clk_100M	<= ~clk_100M;
end

reg		rst_n;

reg				wr_req1, wr_req2, wr_req3;
reg		[7:0]	wrdata1, wrdata2, wrdata3;
reg		[7:0]	wr_addr1, wr_addr2, wr_addr3;
wire			wr_busy1, wr_busy2, wr_busy3;

wire			wr_req_o;
wire	[7:0]	wrdata_o;
wire	[7:0]	wr_addr_o;
reg				wr_busy_i;

reg				rd_req1, rd_req2, rd_req3;
wire	[7:0]	rddata1, rddata2, rddata3;
reg		[7:0]	rd_addr1, rd_addr2, rd_addr3;
wire			rd_busy1, rd_busy2, rd_busy3;

wire			rd_req_o;
reg		[7:0]	rddata_i;
wire	[7:0]	rd_addr_o;
reg				rd_busy_i;

//----------------------仲裁------------------------------------
arb #(
	.is_FULL_DUPLEX	(0),	//是否全双工
	.CHANNEL_NUM	(3),
	.DATA_WIDTH		(8),
	.ADDR_WIDTH 	(8)
)
arb_inst(
	.clk			(clk_100M),
	.rst_n			(rst_n),

	//写通道仲裁
	.wr_req			({wr_req1, wr_req2, wr_req3}),		//CHANNEL_NUM路写通道请求,高电平有效
	.wrdata			({wrdata1, wrdata2, wrdata3}),		//对应的写数据
	.wr_addr		({wr_addr1, wr_addr2, wr_addr3}),	//对应的写地址
	.wr_busy		({wr_busy1, wr_busy2, wr_busy3}),	//回应各个通道是否写忙碌

	.wr_req_o		(wr_req_o),							//输出到实际写入模块的写请求信号
	.wrdata_o		(wrdata_o),							//对应的写数据
	.wr_addr_o		(wr_addr_o),						//对应的写地址
	.wr_busy_i		(wr_busy_i),						//模块是否忙碌

	//读通道仲裁
	.rd_req			({rd_req1, rd_req2, rd_req3}),		//多路读请求,高电平有效
	.rddata			({rddata1, rddata2, rddata3}),		//对应的多路读数据
	.rd_addr		({rd_addr1, rd_addr2, rd_addr3}),	//对应的读地址
	.rd_busy		({rd_busy1, rd_busy2, rd_busy3}),	//回应各个通道是否读忙碌

	.rd_req_o		(rd_req_o),							//输出到实际读模块的读请求信号
	.rddata_i		(rddata_i),							//获取的数据
	.rd_addr_o		(rd_addr_o),						//对应的读地址
	.rd_busy_i		(rd_busy_i)							//模块是否忙碌
);

//-----------------------tb----------------------------------
localparam	WAIT_N	= 20;

wire	wr_req_o_pe;
reg		wr_req_o_d0;
reg		wr_req_o_d1;

wire	rd_req_o_pe;
reg		rd_req_o_d0;
reg		rd_req_o_d1;

always @(posedge clk_100M) begin
	wr_req_o_d0		<= wr_req_o;
	wr_req_o_d1		<= wr_req_o_d0;

	rd_req_o_d0		<= rd_req_o;
	rd_req_o_d1		<= rd_req_o_d0;
end

assign	wr_req_o_pe	= wr_req_o_d0 & (~wr_req_o_d1);
assign	rd_req_o_pe	= rd_req_o_d0 & (~rd_req_o_d1);

reg		[7:0]	wr_busy_cnt		= WAIT_N;
always @(posedge clk_100M) begin
	if(wr_req_o_pe) begin
		wr_busy_cnt		<= 8'd0;
	end
	else begin
		if(wr_busy_cnt <= WAIT_N) begin
			wr_busy_cnt		<= wr_busy_cnt + 1'b1;
		end
		else begin
			wr_busy_cnt		<= wr_busy_cnt;
		end
	end

	wr_busy_i		<= (wr_busy_cnt != 0 && wr_busy_cnt < WAIT_N)? 1'b1 : 1'b0;
end

reg		[7:0]	rd_busy_cnt		= WAIT_N;
always @(posedge clk_100M) begin
	if(rd_req_o_pe) begin
		rd_busy_cnt		<= 8'd0;
	end
	else begin
		if(rd_busy_cnt <= WAIT_N) begin
			rd_busy_cnt		<= rd_busy_cnt + 1'b1;
		end
		else begin
			rd_busy_cnt		<= rd_busy_cnt;
		end
	end

	rd_busy_i		<= (rd_busy_cnt != 0 && rd_busy_cnt < WAIT_N)? 1'b1 : 1'b0;

	rddata_i		<= rd_addr_o;
end

initial begin
	rst_n	<= 1'b0;
	{wr_req1, wr_req2, wr_req3}		<= 3'b000;
	{rd_req1, rd_req2, rd_req3}		<= 3'b000;
	#100;
	rst_n	<= 1'b1;
	#100;

	fork
		begin
			{wr_req1, wr_req2, wr_req3}		<= 3'b101;
			{wrdata1, wrdata2, wrdata3}		<= {8'd12, 8'd34, 8'd56};
			{wr_addr1, wr_addr2, wr_addr3}	<= {8'd1, 8'd2, 8'd3};
			#20;
			{wr_req1, wr_req2, wr_req3}		<= 3'b000;
			wait(wr_busy_i); wait(~wr_busy_i);
			wait(wr_busy_i); wait(~wr_busy_i);
			#100;
		end
		
		begin
			{rd_req1, rd_req2, rd_req3}		<= 3'b011;
			{rd_addr1, rd_addr2, rd_addr3}	<= {8'd1, 8'd2, 8'd3};
			#20;
			{rd_req1, rd_req2, rd_req3}		<= 3'b000;
			wait(rd_busy_i); wait(~rd_busy_i);
			wait(rd_busy_i); wait(~rd_busy_i);
			#100;
		end
	join

	$stop;
end

endmodule

全双工时的结果如下:

在这里插入图片描述

半双工时的结果如下:

在这里插入图片描述

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

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

相关文章

网络协议系统学习

网络为什么要分层&#xff1f; 因为是个复杂的程序就要分层 可以把网络包想象成一个buffer或者一块内存&#xff0c;是有格式的。同时&#xff0c;想象自己是一个处理网络包的程序&#xff0c;而且这个程序可以跑在电脑/服务器/路由器/交换机上&#xff0c;自己有很多网口&am…

抖音seo优化源码搭建/搜索排名系统,技术理论分析搭建中。

抖音seo系统源码SaaS&#xff0b;源码私有化部署搭建&#xff0c;抖音seo源码&#xff0c;抖音seo系统源码&#xff0c;抖音seo系统搭建部署&#xff0c;抖音已经成为了当今最为流行的短视频平台之一&#xff0c;拥有着庞大的用户群体和海量的视频资源。对于一些商家或者运营者…

26岁,几乎零基础,想从基础学习渗透测试该如何进行?

要成为一名渗透测试员&#xff0c;想从基础学习需要先掌握下面这3块&#xff08;文末有相关自学资源推荐&#xff09;&#xff1a;1、学习硬件和网络 渗透测试主要涉及网络和部分涉及硬件。 2、操作系统和系统架构 操作系统和系统架构在渗透测试中起着关键作用。系统操作涉及x…

笔试强训6

作者&#xff1a;爱塔居 专栏&#xff1a;笔试强训 作者简介&#xff1a;大三学生&#xff0c;希望和大家一起进步&#xff01; 1.下列关于ThreadLocal的描述中&#xff0c;错误的是&#xff08;&#xff09; A.ThreadLocal采用线程隔离的方式存放数据&#xff0c;可以避免多线…

社区网格化管理系统

在传统的城市管理过程中存在的问题&#xff1a; 1、问题发现不及时&#xff0c;被管理对象不清楚。 2、管理部门职责不清&#xff0c;协调成本高。 3、城市管理整体情况缺乏数据支撑。 4、基层力量薄弱。 凡尔码搭建社区网格化管理系统依托统一的城市管理以及数字化的平台&…

Codeforces Round 875 (Div. 2)(A—D)

文章目录 A. Twin Permutations1、分析2、代码 B. Array merging1、分析2、代码 C. Copil Copac Draws Trees1、分析2、代码 D. The BOSS Can Count Pairs1、分析2、代码 A. Twin Permutations A. Twin Permutations 1、分析 作者这里的构造方法是让最终的数组满足&#xff…

linux安装jdk8

1.下载jdk8 https://www.oracle.com/java/technologies/downloads/#java8 2.上传jdk &#xff08;1&#xff09;将jdk源码包&#xff0c;上传到/usr/local &#xff08;2&#xff09;进入上传jar包目录 [rootiZ2ze7vthdl3oh0n0hzlu7Z ~]# cd / [rootiZ2ze7vthdl3oh0n0hzlu…

C语言之字符串,内存操作函数详解(一)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C语言学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C语言知识   &#x1f51d;&#x1f51d; 字符串函数 1. 前言&#x1f6a9;2…

电池管理系统 (BMS)

现今的电子设备&#xff0c;小至TWS耳机和可穿戴设备&#xff0c;大至电动汽车&#xff0c;都离不开锂离子或聚合物电池的供电。依据电子设备所需电力的大小&#xff0c;电池组可能由多个电池单元(电芯)排列而成。电池组的充电和放电、输入/输出电压和电流等状态都需要精密监控…

2023年6月DAMA-CDGP数据治理专家认证,你考了吗?

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

小白系统地学习it技术--python的心得体会

我对我所学习的IT技术的理解 一、it技术介绍——python二、我学习python前的准备工作三、学习时的具体操作1. 在pycharm练习python&#xff0c;唯手熟尔&#xff01;&#xff01;2. 在bilibili看python学习视频3. 报错了&#xff0c;CSDN是你的不二选择&#xff01;4.找代码&am…

【开发日志】2023.05 ZENO----PrimitiveCurvature----曲率分析工具(几何体、图像、点云)

Screen Space Ambient Occlusion - TDA362/DIT223 - Computer Graphics Labs (chalmers.se)https://www.cse.chalmers.se/edu/course/TDA362/tutorials/ssao.html GAMES102在线课程-刘利刚 (ustc.edu.cn)http://staff.ustc.edu.cn/~lgliu/Courses/GAMES102_2020/default.html …

我给自己搭建的前端导航网站,你们都别用

欢迎关注我&#x1f970;&#x1f970;&#x1f970; 主页传送门&#xff0c;持续产出有思考的文档&#xff5e; &#x1f4a5; 想法来源 前段时间在工作的时候&#xff0c;因为遇到了一些之前没了解过的知识&#xff0c;所以化身百度cv工程师&#xff0c;上网冲浪寻找灵感&am…

第六十一天学习记录:C语言进阶:C语言预处理1

程序的翻译环境和执行环境 在ANSI C的任何一种实现中&#xff0c;存在两个不同的环境。 第一种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。第2种是执行环境&#xff0c;它用于实际执行代码。 详解编译链接 翻译环境 ![在这里插入图片描述](https:/…

实战:单点登录的两种实现方式,附源码

最近工作有点忙&#xff0c;好久没更新文章了&#xff0c;正好这两天在整理单点登陆相关的文档&#xff0c;今天趁着小孩睡着了&#x1f92b;&#xff0c;赶紧码一篇实战文交差。 概念 单点登录&#xff08;Single Sign-On&#xff0c;SSO&#xff09;是一种身份验证服务&…

机器学习常识 13: PCA

摘要: 主成分分析 (principal component analysis, PCA) 是一种有理论依据的无监督特征提取的线性方法. 1. 特征选择与特征提取 特征选择是指从已有的特征里面选择出一个子集. 例如: 身高、体重、性别、年龄、体温、血相等等, 如果要一个人是否患流感&#xff0c;身高、体重等…

OpenMMLab-AI实战营第二期——1. 计算机视觉与OpenMMLab概述

文章目录 1. 课程内容概述1.1 Openmmlab框架1.2 课程其他说明 2. mmcv安装2.1 正确步骤2.2 debug2.3 错误探索 1. 课程内容概述 个人更关注语义分割和3D方面的内容&#xff0c;所以这里重点记录这两点相关的。 1.1 Openmmlab框架 具体的模块&#xff0c;详见&#xff1a;http…

wy的leetcode刷题记录_Day67

wy的leetcode刷题记录_Day67 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2023-6-1 前言 目录 wy的leetcode刷题记录_Day67声明前言1019. 链表中的下一个更大节点题目介绍思路代码收获 1019. 链表中的下一个更大节点 222. 完全二叉树…

UUOffice 工具箱,一款功能强大的 Excel 办公插件,好用推荐 ~

简介 UUOffice 工具箱,是一款功能强大的Office插件&#xff0c;功能强大&#xff0c;有着各种的单元格及文本的处理工具&#xff0c;自定义扩展函数&#xff0c;批注管理&#xff0c;图片导入导出&#xff0c;工作表汇总&#xff0c;联想输入等等超多实用工具&#xff0c;对日…

奇葩算法——猴子排序

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;猴子排序 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的加入: 林在闪闪发光的社区…