简易CPU设计入门:验证取指令模块
项目代码下载
还是请大家首先准备好本项目所用的源代码。如果已经下载了,那就不用重复下载了。如果还没有下载,那么,请大家点击下方链接,来了解下载本项目的CPU源代码的方法。
下载本项目代码
准备好了项目源代码以后,我们接着去讲解。
本节前言
想要学习本节,前提是,你得是学习过我讲解取指令模块的有关章节。最好呢,你是从本系列专栏的开头,连续地,学习到这里的。否则,知识不完整,你也不知道哪里落下了,即使你来问我,我可能也不知道,你究竟是差在哪里未理解。
下面的四个链接,是我讲解取指令模块的四篇文章。
取指令(一)
取指令(二)
取指令(三)
取指令(四)
以上的四个讲解取指令模块的文章,建议没有学习的同学,还是先去学习一下。如果你学完完了上述的内容,那么,我们可以继续本文的学习。
取指令模块,它指的是【cpu_me01\code\get_instruct.v】代码文件中的模块。取指令模块的代码,我就不贴了。
验证取指令模块的代码,我这里已经是写好了,我来将其内容给贴在下面的代码块中。
`timescale 1ns/1ns
module tb_get_instruct();
reg sys_clk;
reg sys_rst_n;
reg get_inst_en;
reg [15:0] ip;
wire decode_en;
wire [15:0] instruct_code;wire [15:0] ip_buf;
wire [15:0] instruct_code_wire;
wire rd_en;
wire rd_en_d1;
wire rd_en_d2;reg [9:0] cnt;assign ip_buf = get_instruct_inst.ip_buf;
assign instruct_code_wire = get_instruct_inst.instruct_code_wire;
assign rd_en = get_instruct_inst.rd_en;
assign rd_en_d1 = get_instruct_inst.rd_en_d1;
assign rd_en_d2 = get_instruct_inst.rd_en_d2;initial
beginsys_clk = 1'b1;sys_rst_n <= 1'b0;
#60sys_rst_n <= 1'b1;
endalways #10 sys_clk = ~sys_clk;always @(posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)cnt <= 10'd0;else if (cnt < 10'd20)cnt <= cnt + 10'd1;elsecnt <= cnt;always @(posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)beginget_inst_en <= 1'b0;ip <= 16'h0000;endelse if (cnt == 10'd3)beginget_inst_en <= 1'b1;ip <= 16'h0002;endelsebeginget_inst_en <= 1'b0;ip <= 16'h0000;endget_instruct get_instruct_inst(.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.get_inst_en(get_inst_en),.ip(ip),.decode_en(decode_en),.instruct_code(instruct_code)
);endmodule
以上,是验证取指令模块的代码内容了。接下来,我就来讲解代码。
代码讲解
端口声明,连接被验证模块
图1中的代码,是验证模块的前14行的内容。其中,第1行,这个是规定了本仿真验证模块使用的时间尺度。在【1ns/1ns】这部分语句中,左边的【1ns】代表着,本模块的1个时间单位,是1ns。右边的【1ns】用于指定仿真过程中进位取整的精度为1ns。
需要注意的是,如下的写法是错误的。
`timescale 60ns/3ns
这是因为,无论是左边的指定时间单位的数值,还是右边的指定时间精度的数值,只能采用1、10或者100,两边的数值可以相同,也可以不同。
第2行,是规定了本模块的模块名。我们的取指令模块的模块名是【get_instruct】,那么,对该模块的验证,就是在它的前面,加上【tb_】前缀,变为【tb_get_instruct】。
一般地,我们想要验证的模块是什么名字,验证该模块的模块名,都是在被验证模块的前面加上【tb_】前缀。
第3行到第8行,它们对应着取指令模块的输入输出端口。其实我在写仿真验证代码的时候,就是将取指令模块的输入输出端口给复制过来的。复制过来以后,将端口类型【input wire】或者【input】修改为【reg】,将【output wire】或者【output】修改为【wire】,就可以了。
我们可以来看一看取指令模块的端口声明部分。
我们将图2的3到9行,与图1的3到8行做一个对比,就会明白【tb_get_instruct】模块的3到8行的写法了。
我们再回到图1里面。图1的10到14行,声明了几个wire型变量,这几个变量,其实在取指令模块里面都有。我们在图1里面,也就是在【tb_get_instruct】模块里面声明这几个变量,其实是为了将验证模块与取指令模块的对应变量连接起来,以观测取指令模块中相应变量的波形变化情况。
我们来看一看取指令模块声明的几个变量。
在图3中,可以看到,在取指令模块中声明的几个变量,有reg型的,也有wire型的。而在图1的10到14行,我们声明的同名变量,均为wire型的。这是因为,我们在验证模块中声明的变量,是为了与取指令模块中的相应变脸连接起来,实时地观察取指令模块中对应变量的值。想要实现实时观测的效果,而没有仿真的延迟,那么,在仿真验证模块中,我们就需要用wire型变量,来连接取指令模块中的对应变量。
一般来讲,我们若是想要在test bench文件中观测被验证模块中的某一个变量,我们就需要再test bench中声明一个wire型变量,并且用连续赋值语句将验证模块与被验证模块中的相应的变量连接起来。wire型变量,它具备着实时性,可以用来实时观测。
既然提到了连续赋值语句,而且,我们在图1中的10到14行声明几个wire型变量,正是为了与取指令模块中的对应同名变量相连接,那么,我们肯定是在test bench中,用到了连续赋值语句。那么,我们就来看一看我们的连续赋值语句。如下面的代码块所示。
assign ip_buf = get_instruct_inst.ip_buf;
assign instruct_code_wire = get_instruct_inst.instruct_code_wire;
assign rd_en = get_instruct_inst.rd_en;
assign rd_en_d1 = get_instruct_inst.rd_en_d1;
assign rd_en_d2 = get_instruct_inst.rd_en_d2;
上面的代码块,都用到了【tb_get_instruct】模块中所实例化的取指令模块的模块名,【get_instruct_inst】。实例化取指令模块的代码,我们一会儿再看。
从上面的代码块,我们看到,我们的确是通过连续赋值语句,将本验证模块【tb_get_instruct】中的几个变量与取指令模块中的同名变量给连接起来了。
接下来呢,我们再来看一看验证模块中,实例化取指令模块的代码。如下图所示。
图4的写法,其实,也就是一种套路写法。第59行,是模块与实例名。第60行到65行,是【get_instruct】模块与本验证模块【tb_get_instruct】的变量连接情况。写这个变量连接的代码的时候,我是将取指令模块的端口声明部分,给复制过来,然后呢,将端口类型给去掉,把【[15:0]】等等的向量类型也给去掉,仅仅留下端口名。然后呢,在每一个端口名前面加上英文的句点符号。然后呢,每一行的端口右边加上括号,括号内写上本模块的要连接的变量名。
一般地,我去写验证模块的时候,我都将验证模块与被验证模块的连接变量设置为相同的名称。当然了,随着代码复杂度的增加,免不了地,以后,会有被验证模块的端口名与验证模块的连接变量名不一致的情况。
在写实例化代码的时候,在初学阶段,究竟是否要将验证模块的连接变量与被验证模块的端口名设置为相同,这个你自己来决定。我的建议是,你在跟着哪本书或者哪个教程来学习,你就先学习哪种写法。
在我们的专栏里面,在写实例化代码的时候,我倾向于,将被验证模块的端口名与验证模块的连接变量设置为相同的名称。
在图4里面,写完了实例化代码以后,在68行,是【endmodule】字样。也就是,实例化代码,位于【tb_get_instruct】的最后面的位置。
一般地,书写 test bench 代码文件的时候,实例化代码,都是写在最后的位置。至少我这里是这样子来写的。你当然可以自由地设置其书写位置,不过,我确实是这么来写的。貌似,我在学习FPGA开发版的配套教程的时候,里面也是这么写的。
某些个一般的通行的惯例,大家跟着照做就可以了。
系统时钟与系统复位信号
图5中的代码,就是系统时钟与系统复位的逻辑了。对于系统时钟,我在学习FPGA开发板配套教程的时候,一般地,都像图5所示的那样子,将时钟的初始值设置为1,然后呢,每10个时间单位变化一次,20个单位为一个时钟周期。
而对于系统复位信号,则是刚开始的时候,将其设置为0,以进行整个系统的复位操作。然后呢,过了一段时间,将其设置为1。
在我们的系统里,我们规定了,1个时间单位是1纳秒。所以,一个时钟周期为20ns,也就是本系统的工作频率,为50MHz。
1/20ns = 1/(20 × 10^(-9)) = 10^3 / (20 × 10^(-6)) = 1000 ÷ 20 ÷ (10^(-6))
= 50 × 10^6 = 50MHz
我在学习FPGA的时候,基本的时钟频率,就是50MHz。在我们的这个入门型CPU里面,我也将时钟频率,设置为50MHz。
大家还可以在图5中看到,对于系统时钟信号,我用的是阻塞型赋值运算,而对于系统复位信号,我用的是非阻塞赋值运算。大家自己在写 test bench 文件的时候,也可以这么来写。这就是一种惯例。我们所能够见到的 FPGA 开发板教程,大概也是这么来写的。
系统时钟与系统复位信号,都是test bench文件给设计模块发出的激励信号。
cnt变量与剩余的激励信号
如图6所示,在代码的16行,我声明了本测试文件所用的cnt变量。它是用来查数的,用来设置,将有效的激励信号【ip】与【get_inst_en】发送给【get_instruct】模块的时机。
我们来看一看代码。
图7里面,是关于cnt的逻辑,就是查数。系统复位信号起作用时,cnt为0。当系统处于非复位状态时,cnt开始查数,从1查到20,然后停在20这个数上。
图8是【ip】与【get_inst_en】两个变量的逻辑。系统复位信号起作用时,这俩变量的值为0。当检测到计数器cnt的值为3时,两个信号分别被赋予有效的值,【get_inst_en】被非阻塞赋值为1,【ip】被非阻塞赋值为【2】。
这俩信号的有效时间,在本测试文件里面,都是仅有1个时钟周期。过了这个有效的时钟周期以后,【ip】与【get_inst_en】又复位为0了。
在正式的逻辑里,【get_inst_en】的有效时间,的确是1个时钟周期,但【ip】信号的有效时间则并非一个时钟周期。
在设置地址的时候,我将【ip】的值设置成了2。实际上,将其设置为0到3,都是可以的。我在这个项目里,一共往存有指令的 RAM DISK 里面写入了4条指令。这4条指令位于0到3四个地址中。每一个地址,都是2字节长,而非流行的内存条那样的1字节长。
在这里,本来我也可以将激励信号【ip】设置为0的。但是,设置为0以后,大家就看不出,【ip】是何时变为有效的状态了。所以,我故意将【ip】的有效值设置为一个非零值2。你也可以修改代码,将【ip】的有效值设置为1或3,只要能与复位时的0值区分开即可。
本测试代码模块的总体逻辑
总体逻辑,有这么几点。
- 将本模块与被验证模块【get_instruct】中的端口与变量连接起来
- 给被测试模块的系统时钟与系统复位信号输入激励。本测试模块产生的系统时钟与系统复位信号,作为被测试模块【get_instruct】的激励。
- 设置计数器变量cnt,并在某一个时钟周期里,将有效的指令指针信号【ip】与取指令使能信号【get_inst_en】发送给【get_instruct】模块。
上机仿真
代码与总体逻辑,我都讲完了。接下来,我们准备上机仿真。
首先呢,我们还是要新建一个代码文件,文件名为【tb_get_instruct.v】,将这个代码文件放置在【cpu_me01\test_bench\】路径里面。代码文件的内容,本篇文章开头的代码块里的内容就是,大家将其复制到代码文件中就可以了。
关于新建Verilog代码文件,尤其需要注意的是它的文件格式的问题。因为,FPGA的开发平台,有两个软件是比较流行的,一个是Vivado,另一个是Quartus II。而这俩软件在读取代码文件时,所用的文本编码格式是不同的。
为了防止代码的编码格式而带来的小问题,大家可以参照着你学习FPGA开发板的配套教程里面的内容,来设置你的Notepad++的编码格式。你也可以参照着下面的文章链接,来设置编码格式,新建与保存代码文件。
请参阅文章中的第二分节内容学习设置编码格式
如果上面的替换文字所示,请参阅链接中的第二分节的内容,来设置编码格式,建立与保存代码文件。
注意,文件的保存位置,为【cpu_me01\test_bench\】里面。
做好了代码编辑与保存的工作以后,我们来上机仿真。
上机仿真
第1步,打开Quartus II 13.1软件并打开了本项目以后,首先来设置以下项目的顶层模块,将顶层模块设置为设计块【get_instruct】。我们依次选择【Assignments】,【Settings】菜单项,过程如下图所示。
在图10对话框的左侧,点击选择【General】选项,结果如下图所示。
然后呢,在图11所示的对话框里面,找到下图所示的区域。
在红色框线中,输入【get_instruct】,结果如下图所示
然后点击右下角的【OK】按钮。
点击了OK按钮以后,上面的设置会生效,并且会退出对话框。
第2步,新建测试平台。
我们依次选择【Assignments】,【Settings】菜单项,在弹出的对话框的左侧的栏目里,选择【Simulation】,过程如下图所示。
在图15里面的右边,找到下图所示的区域。
在红色框线所示的右侧的框框里,点击右侧的下拉三角号,并保持与图16同样的选择。
然后在图15里面,找到下图所示的区域。
在图17里面,左边有几个单选按钮,请点选中间的单选按钮,跟图17保持一致。然后点击右侧的红色框线所示的按钮,结果如下图所示。
在图18里面,我们点击右侧的【New】按钮,以新建测试平台。结果如下图所示。
在图19的上方,有【Test bench name】一项,我们在它右边的文本框中输入【tb_get_instruct】。结果如下图所示。
之所以输入这个名,是因为,我们本分节所新建的文件名与模块名,都是这个名字。一般地,新建测试平台的时候,都要将测试平台的名字,设置为test bench 代码文件的测试模块名。
设置完了以后,我们再来看看图19所示的对话框中,如下图所示的区域。
这个区域里,有两个单选按钮,我们点选下方的单选按钮,结果如下图所示。
然后呢,【End simulation at:】的紧接着的右边的文本框里,我们可以用来设置仿真时间的数值,最右边的框框里,可以用来选择仿真的时间单位。我们分别将两个框的内容设置为【600】和【ns】,结果如下图所示。
然后呢,我们再来看图19所示的对话框中,如下图所示的区域。
这个对话框,是用来添加测试模块的代码文件的。在【File name】的右边是一个文本框,再往右,是【...】按钮。我们点击三个点按钮,结果如下图所示。
在图25所示的对话框里,我们浏览到【cpu_me01\test_bench\】中的【tb_get_instruct.v】代码文件,然后点击右下角的【Open】按钮,如下图所示。
然后呢,在图27里面,点击右边的【Add】按钮。接着再点击下方的【OK】按钮,如下图所示。
我们再继续点击几次【OK】按钮,直到来到下图所示的对话框。
在图29的右边,我们找到下图所示的区域。
在图30的红色框线所示的区域,有一个下拉三角,我们点击这个三角号,如下图所示。
在图31中,出现了【tb_get_instruct】这一选项,这个就是我们刚刚建立的【tb_get_instruct】测试平台。我们点击选择【tb_get_instruct】,结果如下图所示。
从图32中,我们看到,文本框中的内容,已经变为了【tb_get_instruct】了。这个文本框,是用来设置测试平台的。一个设计项目,可以连接的测试平台有很多。本节,我们是想要将【tb_get_instruct】设置为测试平台。进行好了上述的设置以后,我们点击对话框右下角的【OK】按钮,回到软件的主界面。
第3步,重新编译代码。
我们在软件主界面里找到下述区域。
我们右击图33中的红色框线所示的【分析 & 综合】选项,在弹出的对话框中,点击【Start】选项。或者,如果【Start】选项为灰色显示的情况下,就在弹出的对话框中点击【Start Again】选项。然后呢,看下方的窗口显示。如果有错误,会显示错误信息。我这里的显示结果如下。
终点看红色框线所示的错误与警告信息。错误信息若不是为0,则我们需要修改代码中的错误。如果错误为0,而警告不为0.那么,很多时候,警告信息我们是可以忽略的。此处,我们忽略警告信息。
接下来,我们依次点击【Tools】,【Run Simulation Tool】,【RTL Simulation】,然后,如果你绑定好了 ModelSim 与 Quartus II,则Quartus II 软件会启动 ModelSim 软件。结果如下。
我们来终点关注下方的选项卡。
我们点击【Wave】选项卡,结果如下图所示。
在图37中,我们找到下图所示的区域。
红色框线所示的按钮,为全局当大按钮,点击它,结果如下图所示。
在图39的左边,有这样的区域,如下图所示。
图40中的区域,为信号列表区域,左边是信号所在的文件与信号名,右边是变量类型。中间的,由红色框线标识的粗竖线,可以拖动它,来调整信号名与变量类型所占据的宽度。由图40来看,信号名一列,宽度小了,致使信号名未能完整地显示。我们将红色框线所示的粗竖线向右拖动一些,结果如下。
这回呢,信号名一列的宽度是够了。可是,在波形图里面,各个波形的显示类型,都是十六进制的。我们希望,将它们设置为十进制的显示格式。具体地,我们需要让信号名中的【cnt】的显示格式设置为十进制。我们在图41中最下方的【cnt】变量上,点击鼠标右键,在弹出的菜单中,依次选择【Radix】,【Decimal】,如下图所示。
选择完了以后,我们再去看右侧的波形图,则cnt字段已经是变为10进制的显示了。如下图所示。
接下来,我们在波形图窗口里,用鼠标左键单击一下cnt值为2的竖直区域里面的某一个位置,调出黄色标记线,使其显示在cnt的值为2的区域中,如下图所示。
然后我们点击几次所所示区域的红色框线所示的放大按钮,
将波形图放大到合适的大小,如下面的图所示。
从图46可以看到,在cnt变为3的那个时钟上升沿,
箭头所示的那一行波形,值还是为0。在cnt变为4的上升沿,箭头所指示的那一行的波形变为1。箭头所示的这一信号波形,为【get_inst_en】信号,取指令使能。
为啥取指令使能信号在cnt变为4的那个时钟上升沿变为高电平,而不是cnt变为3的那个上升沿变为高电平,这个属于是非阻塞赋值的知识。
对于非阻塞赋值,此刻,我就当作是大家已经掌握了。如果有些印象模糊,可以阅读下述链接文章,以了解非阻塞赋值的知识。
本文有去讲非阻塞赋值的例子
额,总是讲解以前讲过的知识,我也觉得烦。以后,再涉及讲过了的知识的时候,我会酌情略去一些个细节。
然后呢,我们来关注一下下图所示的区域。
在图47里面,最左边的红色框线,它是【ip】信号,它是cnt变为4的上升沿变为2,之前与之后,都为0。从左往右数的第2个红色框线,在cnt变为5的上升沿,它变为2,它是【ip_buf】信号。最下方的红色框线,它是【instruct_code_wire】信号,它在cnt变为6的上升沿变为0x2010的。最右边的红色框线,它是【get_instruct】模块中的输出信号【instruct_code】,它在cnt变为7的上升沿变为0x2010的。
其余的信号,还有rd_en,rd_en_d1,rd_en_d2,请大家自行分析波形吧。
结束语
本节的内容并不难。但是,我在讲解的时候,我还是觉得不容易讲解。希望大家能听懂吧。祝大家学习愉快。
相关文章:
简易CPU设计入门:验证取指令模块
项目代码下载 还是请大家首先准备好本项目所用的源代码。如果已经下载了,那就不用重复下载了。如果还没有下载,那么,请大家点击下方链接,来了解下载本项目的CPU源代码的方法。 下载本项目代码 准备好了项目源代码以后ÿ…...
【MySQL数据库】MySQL主从复制
文章目录 MySQL主从复制MySQL主从复制的分类MySQL主从复制原理MySQL主从复制的配置步骤MySQL主从复制的同步模式 MySQL主从复制实验环境准备关闭防火墙和 SELinux时间同步主服务器设置从服务器设置 MySQL 主从复制配置主服务器配置从服务器配置(以 Slave1 为例&…...
CDC变更数据捕捉技术是什么?和ETL有什么不同?
一、什么是CDC技术? 变更数据捕获(Change Data Capture,简称 CDC)是一种用于识别和跟踪数据源中发生变化的数据的技术。 工作原理: 1.监测数据源:CDC 工具会持续监测指定的数据源,如数据库表、文件系统…...
一种用于推进欧洲临床中心中风管理的联邦学习平台即服务
论文标题:A Federated Learning Platform as a Service for Advancing Stroke Management in European Clinical Centers 作者信息: Diogo Reis Santos, Albert Sund Aillet, Antonio Boiano, Usevalad Milasheuski, Lorenzo Giusti, Marco Di Gennaro…...
给哔哩哔哩bilibili电脑版做个手机遥控器
前言 bilibili电脑版可以在电脑屏幕上观看bilibili视频。然而,电脑版的bilibili不能通过手机控制视频翻页和调节音量,这意味着观看视频时需要一直坐在电脑旁边。那么,有没有办法制作一个手机遥控器来控制bilibili电脑版呢? 首先…...
opencv dnn模块 示例(27) 目标检测 object_detection 之 yolov11
文章目录 1、YOLO v11 介绍1.1、改进点特性1.2、性能对比1.3、多任务支持 2、测试2.1、官方Python测试2.2、Opencv dnn测试2.3、测试统计 3、训练 1、YOLO v11 介绍 YOLO11是Ultralytics实时目标探测器系列中最新的迭代版本,重新定义尖端的精度、速度和效率。在以往…...
鸿蒙开发融云demo初始化和登录
鸿蒙开发融云IMKit初始化和登录 融云鸿蒙版是不带UI的,得自己一步步搭建。 下面说如何初始化和登录: 一、初始化: /*** desc : 初始化融云* author : congge on 2024-07-12 15:47**/public static initRongIm() {IMEngine.getInstance()…...
手机防窥膜的工作原理是怎样的?有必要使用防窥膜吗?
在信息高度发达的社会中,我们通过手机可以实现非常多的操作,同时手机中有存在许多我们的隐私信息,伴随使用手机的时间增多,手机中的信息也有可能被暴露,尤其是在公共场所旁人很容易通过瞥视你的手机屏幕获取到一些信息…...
【Python_PySide6学习笔记(三十九)】基于QLineEdit实现自定义文本框,用于格式化文本,每四个字符后添加一个空格
基于QLineEdit实现自定义文本框,用于格式化文本,每四个字符后添加一个空格 基于QLineEdit实现自定义文本框,用于格式化文本,每四个字符后添加一个空格前言1、实现要点1.1 继承和初始化1.2 定义textChanged的槽函数1.3 格式化逻辑1…...
23种设计模式口诀速记
设计模式的核心在于提供了相关问题的解决方案,使得人们可以更加简单方便的复用成功的设计和体系结构 23种设计模式,此处不举例,可以去看我上传的资源里面由详细汇总 口诀: 创建:想见员工丹 [抽象工厂、建造者(生成者…...
n > m 将输出文件 m 和 n 合并。 n < m 将输入文件 m 和 n 合并。 有什么区别
在你的描述中,似乎有一点误解。n >& m 和 n <& m 并不是用来合并文件的,而是用于重定向文件描述符(file descriptors)。让我澄清一下这两个命令的确切含义以及它们之间的区别。 n >& m —— 输出重定向 含…...
语言障碍在自闭症儿童中的表现及应对
自闭症儿童常常面临着语言障碍的困扰,这给他们的成长和发展带来了巨大挑战。 语言障碍在自闭症儿童中的表现形式多样。比如,有个叫小明的自闭症儿童,已经五岁了却还只会说一些简单的词语,如 “爸爸”“妈妈”“要” 等,…...
(成功解决)ubuntu22.04不小心更新成了atzlinux12.7.1,右上角出现红色错误符号
文章目录 🌕问题🌕查看系统版本🌕为什么更新更成了atzlinux🌕通过修复依赖关系尝试解决右上角红色错误符号🌕把源换成ubuntu的源🌕删除atzlinux源和自定义的第三方源🌕重新创建/etc/os-release文…...
005 C#语言基本元素概览,初识类型,变量与方法
构成C#语言的基本元素 标记 :C#编译器可以识别的文本 关键字(Keyword)操作符(Operator)标识符(Identifier)标点符号文本注释和空白 简要介绍数据据类型、变量与方法 变量是存放数据的地方,简称数据 方法是处理数据的逻辑,简称算法 程序…...
Spring Cloud --- Sentinel 授权规则
授权规则概述 在某些场景下,需要根据调用接口的来源判断是否允许执行本次请求。此时就可以使用 Sentinel 提供的授权规则来实现,Sentinel 的授权规则能够根据请求的来源判断是否允许本次请求通过。 在 Sentinel 的授权规则中,提供了 白名单…...
计算机网络基础 - 传输层(1)
计算机网络基础 传输层概述多路复用与解复用概述解复用的工作原理无连接多路解复用面向连接的多路复用 无连接运输:UDP概述UDP 主要应用UDP 报文段结构 可靠数据传输的原理概述构建可靠数据传输协议经完全可靠信道的可靠数据传输:rdt1.0经具有比特差错信…...
Chrome DevTools:Console Performance 汇总篇
Chrome DevTools Chrome 开发者工具是一套 Web 开发者工具,直接内置于 Google Chrome 浏览器中。 开发者工具可以帮助您即时修改页面和快速诊断问题,最终帮助您更快地构建更好的网站。 一、开启 DevTools 右上角菜单 > 更多工具 > 开发者工具 页面…...
【Spark | Spark-Core篇】RDD行动算子action
使用转换算子是产生一个新的rdd,此时在driver端会生成一个逻辑上的执行计划,但任务还没有执行。但所谓的行动算子,其实就是触发作业执行的方法(runJob)。底层代码调用的是环境对象的runJob方法。 1. reduce 函数源码&…...
23.Redis核心数据结构
一、String(k-v) 字符串常规操作 备注 应用场景 SET key value 存入字符转键值对 单值缓存、对象缓存 MSET [key value, key value] 批量存储字符串键值对 对象缓存 SETNX key value 存入一个不存在的键值对 分布式锁 GET KEY 获取一个字符串键值 MGET [key,key,…...
免费送源码:Node.JS+Express+MySQL Express 流浪动物救助系统 计算机毕业设计原创定制
摘 要 随着互联网大趋势的到来,社会的方方面面,各行各业都在考虑利用互联网作为媒介将自己的信息更及时有效地推广出去,而其中最好的方式就是建立网络管理系统,并对其进行信息管理。由于现在网络的发达,流浪动物救助系…...
基于Java+Springboot+Vue开发的旅游景区管理系统
项目简介 该项目是基于JavaSpringbootVue开发的旅游景区管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的旅…...
Python 实现的风控系统(使用了kafka、Faust、模拟drools、redis、分布式数据库)
以下是一个使用 Python 实现的风控系统示例,涵盖以下技术组件: Kafka 消息中间件:用于实时接收支付业务系统传递的交易数据。Faust(Kafka Streams 的 Python 等价):用于流式处理 Kafka 中的消息。规则引擎…...
Linux运维_Rocky8 安装配置Zabbix
Zabbix 是一个开源的监控解决方案,用于监控网络、服务器、应用程序和服务的性能。它提供实时监控、数据收集、告警通知以及图形化界面,方便用户查看和分析监控数据。Zabbix 支持多种数据收集方式,包括 SNMP、IPMI、JMX 和自定义脚本ÿ…...
jQuery Mobile 滚屏事件
jQuery Mobile 滚屏事件 在移动开发中,滚屏事件是一个非常重要的交互方式,它可以让用户通过滚动屏幕来浏览内容。jQuery Mobile 是一个流行的移动框架,它提供了一套丰富的组件和事件,使得在移动设备上实现滚屏效果变得简单。本文将详细介绍 jQuery Mobile 中的滚屏事件,包…...
3.1.1ReactOS系统中搜索给定长度的空间地址区间函数的实现
系列文章目录 //搜索给定长度的空间地址区间 MmFindGap(); PMADDRESS_SPACE AddressSpace,//该进程用户空间 ULONG_PTR Length,//寻找的空间间隔大小 ULONG_PTR Granularity,//粒度位,表明空间起点的对齐要求,注意是起…...
arm64系统不支持32位的解决armel armhf
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...
【毕业设计】工具大礼包之『Maven3.6.3安装与配置』
系统版本 电脑系统:Windows 10 一.Maven下载 🎯 统一版本 apache-maven-3.6.3,下面两种下载方式2选1即可 1.官网直下 官网下载地址 https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/ 找到apache-maven-3.6.3-bin.zip 云盘…...
gin入门教程(9):路由分组与路由版本控制
在使用 Gin 框架构建 RESTful API 时,路由分组与版本控制是一种常见的实践,可以帮助你更好地管理不同版本的 API。下面是如何在 Gin 中实现路由分组和版本控制的示例。 目录结构 /hello-gin │ ├── cmd/ │ └── main.go ├── api/ │ ├── v1/ │ │ └─…...
rt-thread移植SystemView中遇到的问题
源代码地址dujunqiu/SystemView 我使用的rt-thread版本是5.2.0,应该是rt-thread适配的还有点问题 报错处理 1:warning: #223-D: function “typeof” declared implicitly 如下 typedef 的warning是C99规范没有typedef的定义,需要在keii中…...
【C++STL】list的模拟实现
✨ Blog’s 主页: 白乐天_ξ( ✿>◡❛) 🌈 个人Motto:他强任他强,清风拂山冈! 🔥 所属专栏:C深入学习笔记 💫 欢迎来到我的学习笔记! 一、三个类与成员函数接口 在list.…...
做的好的淘宝客网站/佛山网站建设公司
时间:2012年9月27日 地点:鼎好大厦10层 考试时长:1小时 一, 选择题 1,求z的结果 [cpp] view plaincopy print?#define N 3 #define Y(n) ((N1)*n) z 2*(NY(51)); 解答࿱…...
淄博亿泰网站建设推广/产品宣传方案
字符串去除前后空格 void trim(string &s){if(!s.empty() ){s.erase(0, s.find_first_not_of(" "));s.erase(s.find_last_not_of(" ") 1);} }对map和set进行排序 可以将元素项转换为vector的元素,然后排序后输出 #include <iostream> #inclu…...
用dw做的网站怎么发布/网络游戏推广平台
2019独角兽企业重金招聘Python工程师标准>>> 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 闭包的定义及其优缺点 闭包 是指有权访问另一个函数作用域中的变量的函数&#x…...
软件园二期做网站的公司/外贸seo优化公司
oracle 中的常量和变量:变量:通过变量,可以把需要的参数传递进来,经过处理后还可以把值传出去,最终返回给用户。常量:常量是代码中固化的信息,常量的值从定义开始就是固定的。常量主要用于为程序提供固定和…...
b站推广入口mba智库/官网百度
UDP数据包接收逻辑的优化修改以及对性能的影响 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <signal.h> #include <arpa/inet.h> #in…...
西宁 专业网站建设/上海seo关键词优化
import shelvefshelve.open(rshelve)#f[stu_info] {name:john,age:18} #f[stu2_info] {name:tom,age:20} #f[stu3_info] {name:jey,age:19} #f.close()print(f.get(stu_info)[name]) 转载于:https://www.cnblogs.com/liujinjing521/p/11320632.html...