简易CPU设计入门:验证系统初始化模块(二)

在前两节,我是讲解了系统初始化代码与系统初始化的验证代码。

本节,我在前面两节的基础上,来讲解系统初始化代码中的【init_done】信号变为高电平的逻辑。

想要学习本节内容,请自行回顾如下所示的两节内容。

系统初始化代码

验证初始化代码(一)

同时呢,我也要求,你得是已经下载了本项目的配套源代码。若是还没有下载,请浏览如下章节,了解下载方法。

下载本项目代码

下载好了代码以后,请大家自行打开【cpu_me01\code\sys_init.v】。

至于上一节的验证代码,我再将其贴出来一次。

`timescale 1ns/1ns
module tb_sys_init();
reg sys_clk;
reg sys_rst_n;
wire init_done;
 
wire [9:0] cnt;
assign cnt = sys_init_inst.cnt;
 
initial
begin
	sys_clk = 1'b1;
	sys_rst_n <= 1'b0;
#60
	sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
sys_init sys_init_inst
(
	.sys_clk(sys_clk),
	.sys_rst_n(sys_rst_n),
	.init_done(init_done)
);
endmodule

接下来,我们来讲解系统初始化模块中的【init_done】变量。

一.   非阻塞赋值的复习

在这里,我之所以要去讲解一下init_done变量的变化情况,其实就是为了讲解一下非阻塞赋值的知识。

非阻塞赋值,这算是一个难点知识。

在行为级语句里面,有一种赋值语句,叫做过程赋值语句。过程赋值语句分为两种类型,一种叫做阻塞型赋值,一种叫做非阻塞赋值。

非阻塞赋值的执行分为两个阶段。

第一阶段,计算右侧表达式的值,并且在计算的时候,使用的是各个变量的旧值。

第二阶段,在相应的仿真时刻,将右侧表达式的计算结果,赋给左侧的变量。

也就是,第一阶段是计算右侧表达式,第二阶段是将结果赋给左侧变量。第一阶段为计算表达式,第二阶段为正式赋值。

非阻塞赋值语句,常常用在时序逻辑代码中,与时钟信号相关联。

二.   init_done信号

接下来,我来讲解系统初始化模块中的【init_done】信号。

我们先来看一看cnt变量的情况。

图1

cnt变量是一个10位的reg型变量。由图1可知,在系统复位信号变为高电平以后,cnt变量开始正常计数,从1计数到20.到了20以后,保持不变。

然后呢,我们来看init_done信号。

图2

由图2可知,在检测到cnt等于9的时候,init_done被非阻塞赋值为1,并且,仅仅在cnt等于9的时候,init_done才被非阻塞赋值为1。等到检测到cnt为10的时候,init_done又会被非阻塞赋值为0。也就是,init_done的高电平仅保持一个时钟周期。

那么,请问,当init_done变为高电平的瞬间,它是处在【cnt == 9】的左沿,还是处于【cnt == 10】的左沿呢?

我先揭晓答案,是处在【cnt == 10】的左沿。为什么是这种结果,这是我在这一节要去分析的。关于非阻塞赋值的问题,我觉得挺难的。到现在,我也不能说完全掌握了这一知识点。但是呢,我所掌握的部分,我自己的一点理解,我会把它分享给大家。

我说的也不一定对。如果你有更好的理解,也欢迎批评指正。

接下来,我来分析这个过程。

(1)初始条件,假定【cnt == 8 && sys_rst_n == 1】

过了一会儿功夫,时钟的上升沿到来了,对cnt信号进行检测,发现它是小于20的,所以,cnt会被非阻塞赋值为9。我们要对这一过程进行细化。

图3,初始条件后的第1个时钟上升沿到来,cnt的变化

图3所示的表格,相信,应该是不难理解的。在这里,我们需要明确的是,为什么说,在第一阶段的时候,cnt依然保持原值,而不是赋值为新值9呢?因为按照非阻塞赋值的原理,它是在第二阶段,才被赋予新值9的。在第一阶段,仅仅是计算得到了新值9,但是这个新值并未被赋给cnt变量,所以,在第一阶段,cnt仍然为旧值8,而非新值9。但是呢,新值已经是被计算出来了。

然后呢,到了第二阶段,cnt才被赋予新值9。

经过这样的讲解,我相信,图3中所说明的问题,大家应该是已经理解了。这段讲解,应该是不难的。那么,接下来呢,我稍微地来扩充一下子这个表格,让它包含更多的时钟信号。

图4,分析cnt变量

对于上面的表格,请大家自己去看一看。在这里呢,它都是说,某一个时钟上升沿到来后,在第一阶段,cnt保持原值。在第二阶段,cnt变为新值。这个呢,我们在图3里面,应该就已经是理解了。

在这里呢,有一个新的理解点,是在上升沿到来时,cnt的值。如果在时钟上升沿的瞬间,去检测cnt的值的话,那么,它的值,其实就是cnt变量的旧值,而非非阻塞赋值后的新值。也就是,某一个时钟上升沿到来的时候,如果在这个时候,去检测cnt的值的话,那么,这个时候的cnt变量的值它和第一阶段中cnt的值是一样的。这是另外一个重要的知识点。请大家好好地去理解和回味一下子这个知识点。

对于图3和图4,这两张图所涉及的非阻塞赋值的知识点,请大家,好好地来回味一下子。尤其是说,当你还没有很好地理解非阻塞赋值的时候,这两张图呢,你尤其是需要好好地来回味一下子了。

我个人的学习体会是,学习的时候,阅读新内容,学习新的知识点是一方面。而对于一些个重点,难点,多读几遍,多沉思,这种品味,这种停留,沉淀,其实是学习的一个重要的过程。有的东西呢,如果不好转过来这个弯,那么,你就可以多去看两遍,可以掩卷沉思,可以在这个地方,停一停,让自己适应和回味一会儿。这种沉淀的过程,我认为,它应该也算是学习过程中的重要一环。

我不知道你的智力水平是怎样的。也许呢,你学习新知识,理解重难点知识的时候,你比我掌握得快。但是呢,如果你学习新知识,理解重点难点的时候,你的情况跟我差不多,我还是建议,你显停留一会儿,把这个重难点的部分,先去沉淀那么一会儿。这种沉淀的过程,应该是有助于适应和理解新知识的。

理解好了以后,我们再来扩充一下图4所示的表格,将init_done信号也给加进来。如下图所示。

图5,对cnt与init_done信号的综合分析

对于 上面的这个图呢,还请大家自己去细看一下啊。

在这里呢,cnt的变化与前面相同,第一阶段保持原值,第二阶段变化为新值10。而我们要重点关注的,是init_dopne信号的变化。

关于init_done信号,在它的检测代码里面,它检测的是cnt的值。在检测的时候,它检测到的,是cnt变量的旧值,而非cnt被非阻塞赋值后的新值。

在第1个上升沿到来时,cnt的值,为8。所以,在init_done信号所在的代码块里面,检测到的cnt的值为8。由于检测到的值是8而不是9,所以,init_done信号在第二阶段依旧为0。

在第2个上升沿到来时,cnt的值为9。此时,在init_done信号所在的代码块里面,检测到的cnt的值为9,符合了init_done变为高电平的条件。所以,在第一阶段,init_done保持原值0,在第二阶段,init_done变为高电平,变为1值。

在第3个上升沿到来时,cnt的值为10。此时,在init_done信号所在的代码块里面,检测到的cnt的值为10,符合init_done信号所在的代码块中的【else】部分的条件,所以 呢,在第一阶段,init_done保持原值中的高电平,而到了第二阶段,就变回了低电平。

以上的分析,是我对与cnt与init_done信号的波形变化的分析。这里也包含着我对于非阻塞赋值的理解。

这一部分的理解,算是我个人的一种理解。对于非阻塞赋值的细节变化,大家在ModelSim里面是看不到的,仅能够通过猜想,通过逻辑分析的方式,来理解其中的变化。

我的理解就是这样的。

本节的知识,说多不多,说少也不少。对于我在上面所展示的几张表格,还请大家多看一看,多想一想。我认为,这一块,是很重要的。

而且呢,这种理解,它与大家之前在别的教材上对于非阻塞赋值的讲解,可能是不一样的。所以呢,对此,我觉得,大家最好是能够把这一节,好好地来想一想。

究竟我说的对不对,有没有哪些个地方,说的不严密,你呢,你都可以好好地去想一想。

最好呢,你自己可以写一些个其他的代码,来验证一下子。验证的话,那就是通过ModelSim的波形图,来进行验证了。当然了,验证的一个基础条件就是,时钟的频率,应该是频率不太高的场景。比如100Mhz,50Mhz,都可以。如果是几个Ghz的高频场景,那你就不要用我的这种分析了。

我目前对于Verilog HDL的学习,也仅仅限于50Mhz,100Mhz等等的,频率不太高的场合。对于几个Ghz的那种高频场合,我暂时还没有能力去研究。

三.   init_done信号在cnt的哪个边沿变为高电平呢

我们还是得回到图5或者是图4。

虽说,在第1个上升沿到来时,检测到的cnt值为8,但是,通过非阻塞赋值,在第1个时钟上升沿到来后的第二阶段,cnt会变为9。由于两个阶段的时间间隔非常小,且我们一般都会在test bench文件中设置【`timescale 1ns/1ns】,所以,在ModelSim里面查看波形的时候,cnt在第1个时钟上升沿到来的时候,当时就变为9了。

在ModelSim里面,看不到非阻塞赋值的两大阶段的细微变化。这一变化,只能是由我们自己去分析,去假设和验证。

这样的话,从第1个上升沿开始,到第2个上升沿到来之前,ModelSim里面展示的cnt的值为9。

从第2个上升沿开始,到第3个上升沿到来之前,ModelSim里面展示的cnt的值为10。

ModelSim的波形图变化如下所示。

图6

我们在ModelSim的波形图中也看到了,以【cnt == 8】作为初始条件,它之后的第1个时钟上升沿,init_done为低电平。它之后的第2个时钟上升沿,init_done变为高电平,且仅保持一个时钟周期。初始条件之后的第2个时钟上升沿,正好是位于【cnt == 10】的左沿的位置,而不是位于【cnt == 9】的左沿位置。

结束语

对于本节的讲解,也就是我本人对非阻塞赋值的理解,还是请大家务必 要多看,多思考和品位一下。这算是Verilog中的一个重点知识。这块呢,我觉得是需要认真对待的一点。

在学习知识的时候,有的地方,确实是需要学的精准一些。如果理解得模模糊糊,不透彻,这在平时的小项目里面,或许没啥。但是呢,对于重大的项目来讲,这种模糊理解,可能就会造成一定的障碍了。如果想要锤炼自己的技术,我认为,某些个地方,也是需要有着精准的理解和掌握的。

如果缺乏对一些个知识点的精准理解,那么,这应该是会对个人的能力提升,带来一定的不良影响。

在这里呢,我打算培养的,是这种操作系统与处理器方面的精英人才,我要求能跟下来课程的人,尽量地,把能力,提升到精英的级别。咱们这里,尽量地,不要浅尝辄止。

我自己能力有限,有的地方,可能我的理解,也不到位,还可能存在着理解错误的情况。但是呢,我自己能理解的地方,我会力求将其讲好。

本系列里面,我讲解的是简易CPU代码。以后呢,我有可能会写出来一个逻辑复杂一些的CPU。如果我有能力写出来那种,逻辑复杂一些的,性能优越一些的CPU,那么,我也会尽量地,把它们给讲出来。

我是希望能够这种讲课,带出来一批精英程序员。必须得是带出来一批精英程序员,而且数量必须得是足够。如果是说,人才很多,但是呢,达不到高端的要求的话,那么,很难说,能够开发出英特尔与ARM级别的优秀的处理器来。如果是达到了技术的高端的要求,然而,人数不足,我估计也开发不出来英特尔与ARM级别的高端处理器。

如果有心提升自己的编程水平,有心获得高收益的话,我还是希望,看我的当前的专栏,以及以后的专栏的同学,能够把技术,锤炼到精英的层次,而不要浅尝辄止。

  • 43
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值