河曲智叟 发表于 2024-12-31 03:37:09

浅易CPU计划入门:本系统中的通用寄存器(三)

项目代码下载

请各人首先准备好本项目所用的源代码。如果已经下载了,那就不消重复下载了。如果还没有下载,那么,请各人点击下方链接,来了解下载本项目的CPU源代码的方法。
下载本项目代码
准备好了项目源代码以后,我们接着去讲解。
本节媒介

在上一节,我是讲解了寄存器元素模块的两行注释与一行参数声明代码。本节,我们要来讲解着变量声明的部分。
在讲解代码之前,还是请各人在下载了项目压缩包和解压缩以后,打开本节对应的代码文件。
本节代码文件,主要是指位于【......cpu_me01\code\Ctrl_Center\】路径里面的【register_element.v】。
一.    与寄存器ID相关的线网变量

   https://i-blog.csdnimg.cn/direct/cbbc918e31b44e5e9b240ae19c9601f9.png   图1    图1,为本节所讲解的变量声明部分。在这里,我还将上一节讲过了的参数声明代码也给包罗了进来。之以是要包罗参数声明部分,是由于,在第27行声明的 reg_id 变量与参数有着密切的关系。
图1中的27行,声明的变量,与参数 REG_ID 仅仅是巨细写差别。我们再来看第29行的代码。
第29行代码,将 REG_ID 的值赋给线网变量 reg_id。这种赋值,似乎是没有必要的。由于,在代码中,使用 reg_id 的地方,实在都可以用 REG_ID 来代替。这么写,算是我个人的一种习惯。你也可以不采取我的写法。
二.    带有代理性质的reg型变量

我们来看第19行代码,它是声明了一个reg类型的变量,【data_sig_represent】。它和模块开头的信号声明部分的【data_sig_inner】一样,都是16位的。那么,请问,两者是什么关系?
回答是,【data_sig_represent】是【data_sig_inner】的代理。
我们请看下图所示的代码。
   https://i-blog.csdnimg.cn/direct/b32d477b6d0540ef807463fec85c8de9.png   图2    在图2所示的95行代码中,我们看到,我们用一连赋值语句,将reg型变量【data_sig_represent】的值赋给了线网变量【data_sig_inner】。由于是一连赋值语句,以是呢,每当【data_sig_represent】变化时,【data_sig_inner】的值会立即变化而且与【data_sig_represent】的新值相等。
既然两个变量的值相等,那么,我们干脆只用【data_sig_inner】就好了,为啥还要多此一举,设置【data_sig_represent】这个代理变量呢?
这是由于,在寄存器元素模块中,我们需要让【data_sig_inner】加入时序逻辑的运算,要求它在非壅闭赋值中加入运算。
然而,在Verilog HDL中,wire型变量,不可以用于过程赋值语句的左侧变量,不可以用于时序逻辑运算中的左侧变量。
   https://i-blog.csdnimg.cn/direct/81719f99dea048969ff6d0735eb951ad.png   图3    在图3里面。我们暂且不关注 reg 型变量【data_sig_represent】的逻辑。在图3中,reg型变量,可以放在【data_sig_represent】的位置上,而线网类型的变量是不可以放在【data_sig_represent】的位置的。
在一个过程赋值语句中,大概是一连赋值语句中,赋值符号【=】大概【<=】左侧的变量,可以叫做左值。
wire型变量,不可以用于过程赋值语句的左值。过程赋值语句,它包括非壅闭赋值语句和壅闭赋值语句两种类型。wire型变量,在这两种类型的过程赋值语句中,都是不可以使用的。然而,reg型变量,它是可以用于过程赋值语句的左值的。
wire型变量【data_sig_inner】,不可以用于非壅闭赋值语句的左值,而我们又需要让它加入时序逻辑运算,让它成为非壅闭赋值语句的左值,在这种情况下,我们可以采取的一种做法,那就是申请一个reg型变量,让它作为wire型变量【data_sig_inner】的分身,来加入时序逻辑运算,并作为非壅闭赋值语句的左值。
在代码中,我们给wire型变量【data_sig_inner】设置的分身,便是 reg 型变量【data_sig_represent】。【data_sig_represent】的逻辑代码,正是图3中所示的代码。在这里,我们暂且不讲关于【data_sig_represent】的逻辑。我们本节也不会讲。在以后的分节里面,我们会去讲解的。
设置了 reg 型变量【data_sig_represent】以后,它还仅仅是一个单纯的 reg 型变量,它还不是【data_sig_inner】的分身。怎样让【data_sig_inner】与【data_sig_represent】建立绑定关系呢?
通过图2中的95行代码所示的一连赋值语句,就可以建立【data_sig_inner】与【data_sig_represent】的绑定关系了。
我们还是回到图1,。
   https://i-blog.csdnimg.cn/direct/cbbc918e31b44e5e9b240ae19c9601f9.png   图1副本    在图1里面,在20行,我们建立了另一个代理性质的变量,reg 型的【work_ok_represent】变量。
在图2中,在96行,我们看到了【work_ok_represent】与【work_ok_inner】的绑定关系、在本代码文件中,【work_ok_represent】是【work_ok_inner】的时序逻辑代理。
三.    节奏变量

在这里,我们来讲解图1中的第21行到第25行的代码。
这几行代码里面,它是分为两组。
【get_time】,【get_time_d1】和【get_time_d2】是一组,而【write_time】与【write_time_d1】是另一组。
我先来将get_time组变量。
【get_time】变量用来标识一个基准的时刻。【get_time_d1】是比【get_time】耽误一个时钟周期的信号,而【get_time_d2】是比【get_time】耽误两个时钟周期的变量。
假定,初始条件里面,三个变量的值,均为0。
然后呢,get_time的值,在后续的几个时钟的上升沿,依次变化为1,0,1,1。再今后,get_time的值就都是0了。在这种情况下,我们来看get_time,get_time_d1与get_time_d2的变化情况
初始条件:get_time == 0,   get_time_d1 == 0,    get_time_d2 == 0.
1号上升沿:get_time == 1,   get_time_d1 == 0,    get_time_d2 == 0.
2号上升沿:get_time == 0,   get_time_d1 == 1,    get_time_d2 == 0.
3号上升沿:get_time == 1,   get_time_d1 == 0,    get_time_d2 == 1.
4号上升沿:get_time == 1,   get_time_d1 == 1,    get_time_d2 == 0.
5号上升沿:get_time == 0,   get_time_d1 == 1,    get_time_d2 == 1.
6号上升沿:get_time == 0,   get_time_d1 == 0,    get_time_d2 == 1.
7号上升沿:get_time == 0,   get_time_d1 == 0,    get_time_d2 == 0.
从上面的变化列表可以看出,get_time一组的值的变化是相同的,只不过,存在着节奏耽误的情况。
get_time一组是这样的耽误情况,write_time与之类似,只是这一组里面只有两个变量而已。
那么,设置这种节奏变量有什么意义吗?
有的。无论是做广播体操,还是排练舞蹈,都需要有节奏。舞蹈有了节奏,舞蹈的人,都按照节奏来演练动作,那么,各人的动作就都可以整齐划一了。广播体操有了节奏,学生们也可以大致保持动作的整齐,而不至于乱成一锅粥。
固然了,实际在做广播体操的人,很多多少人是不去认真做的。但是呢,有了节奏以后,纵然部分人只是慵懒得伸伸胳膊,伸伸腿,大要上的动作,也是整齐划一的,而非你做你的我做我的,你打排球我练太极拳,你躺着我趴着。
我们这几节,要讲解的东西,是寄存器元素模块,以及寄存器的读写操作。那么,我们设置节奏,就是想要确定,对于寄存器的读操作大概写操作,何时进行特定的操作,何时完成。有了这种节奏变量,可以使寄存器的读写操作有序进行,不至于紊乱。
关于节奏变量,我们就先讲到这里吧。在后续的几节,我们还是会具体地来讲解着节奏变量的内容的。
在本节,我们可以对节奏变量有一个大致的印象。
结束语

本节的内容,应该是不难理解吧。既然不是很难,那么,盼望各人能够学好本节知识。
各人再见。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 浅易CPU计划入门:本系统中的通用寄存器(三)