天空闲话 发表于 2025-1-3 18:23:38

浅易CPU计划入门:内存读写(二)

项目代码下载

请大家起首准备好本项目所用的源代码。如果已经下载了,那就不消重复下载了。如果还没有下载,那么,请大家点击下方链接,来相识下载本项目的CPU源代码的方法。
CSDN文章:下载本项目代码
上述链接为本项目所依据的版本。
在解说过程中,我还时不时地发现自己在解说与解释上的一些个错误。偶然,我还会添加一点新的资料。在这里,我将动态更新的代码版本发在下面的链接中。
Gitee项目:浅易CPU计划入门项目代码:
授课的时间,我主要依据的是CSDN文章链接。然后呢,如果你为了得到我的最近更新的版本,那就请在Gitee项目链接里下载代码。
准备好了项目源代码以后,我们接着去解说。
本节前言

在上一节,我是解说了【rw_ram】模块的端口声明与变量声明的部分。本节,我来将内存写操纵。
本节的代码,主要位于【...cpu_me01\code\Ctrl_Center\】路径内里,所所涉及的代码文件,主要是【rw_ram.v】和【ctrl_center.v】。
一.    内部控制信号

   https://i-blog.csdnimg.cn/direct/b5437dae8c344777ab9235887abe0b93.png   图1,控制中央模块的解释代码    /*********************************************
ctrl_sig_inner:register write enable:寄存器写使能
ctrl_sig_inner:register read enable:寄存器读使能
ctrl_sig_inner:random memory write ebable:内存写使能
ctrl_sig_inner:random memory read enable:内存读使能
ctrl_sig_inner:Arithmetic and Logic calculate:算术逻辑运算
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
ctrl_sig_inner:reserve:保留
还有一种运算叫做读取立即数,将立即数放入内部寄存器。
此运算不需要通过内部信号的参与。
************************************************/ 在图1中,我们偏重看40行的代码。它的意思是说,当内部控制信号总线的位2为1,别的位都是0的时间,它代表的是,控制中央发布了内存写使能信号。
接下来呢,我们来看一看。当检测到有效的内存写使能信号以后,都有哪些变革。
二.       write_time 与 wr_en

   https://i-blog.csdnimg.cn/direct/cc5e148b52a1454aab460ae8bfa456d7.png   图2,内存读写模块的代码    从图2可以看到,write_time属于是这样的一种范例的变量。平时的时间,它是0值。只有在满足特定的条件的时间,它才变为高电平。
这个特定的条件,就是内部控制信号总线【ctrl_sig_inner】的位2为1。
当内部控制信号总线【ctrl_sig_inner】的位2为1时,代表着,控制中央发布了内存写使能信号。这个内部控制总线上的内存写使能信号仅仅是维持一个时钟周期,随后,内部控制总线将会处于高阻态状态。
所以呢,在这里,【write_time】维持高电平状态的时间,也是只有一个时钟周期。别的时间,它都是0值。
我们再来看一看【wr_en】的逻辑。
   https://i-blog.csdnimg.cn/direct/8b067aefae7749fcb080ab6646167a05.png   图3    从图3可以看出,【wr_en】的逻辑是,当检测到【write_time】为1的时间,【wr_en】被非壅闭赋值为1,别的时间,为0值。
由于write_time仅维持一个时钟周期的高电平,所以呢,【wr_en】的高电平时间,也仅仅维持一个时钟周期。
三.    内部地址信号与内部数据信号的缓存

   https://i-blog.csdnimg.cn/direct/25553a3afce84177b3348b778eedcca7.png   图4    在图4内里,我们本节仅仅关注红色框线所示的部分的代码。
从图4的红色框线的代码部分来看,在系统复位信号为低电平有效时,也就是在系统复位的时间,地址缓存变量【addr_buf】与数据缓存变量【data_buf】被非壅闭赋值为0值。而在平时,没有特殊条件的时间,【addr_buf】与【data_buf】会保持它的现有值不变。
而在内部控制信号总线变量【ctrl_sig_inner】的位2为1时,也就是控制中央发布了内存写使能信号的时间,【addr_buf】会缓存内部地址信号总线变量【addr_sig_inner】的值,【data_buf】会缓存内部数据信号总线变量【data_sig_inner】的值。
也就是说,【addr_buf】与【data_buf】的逻辑是,系统复位时,它俩都被赋予0值。接下来呢,在不思量别的条件的情况下,每次内部控制信号总线变量【ctrl_sig_inner】的位2为1时,这两个缓存变量,都来缓存一次对应的内部地址总线变量与内部数据信号总线变量的值。然后呢,寻常的时间,保持原值不变,直到再次检测到内部控制信号总线变量【ctrl_sig_inner】的位2为1时,再将【addr_buf】与【data_buf】非壅闭赋值为新的对应的内部地址信号总线变量与内部数据信号总线的值。
四.    内存读写模块内里,对 RAM IP 核的实例化代码

   https://i-blog.csdnimg.cn/direct/787658ec4789423b839a130ff45b5ccd.png   图5    图5,展示的是 RAM IP 核的实例化代码。对于 RAM IP 核的天生方法,我们本节不去细讲。想要相识本项目所使用的 RAM IP 核的天生方法与参数配置,请参考下述链接所示的文章。
调用IP核天生指令内存
点击了链接以后,请找到第二分节,在二号分节内里查察天生方法与参数配置。。
在确保你已经相识了本项目的 RAM IP 核的天生方法以后,你可以接着看下面的解说。
从图5的133行可以看到,我们的【rw_ram】模块所实例化的模块和模块名分别为【ram_256x16】和【ram_256x16_inst】。模块名中的【256x16】体现说,这个 RAM IP 核,包罗了256个内存单位,每个内存单位是16位,也就是2字节。
接下来,是信号连接部分。
对于内存写操纵来说,我们需要使用的信号连接,位于134行,135行,136行,137行和139行。
在134行内里,我们可以看到,在 RAM IP 内部,使用的复位信号的名称为【aclr】。它的英文全名是【asynchronous clear】。不外呢,这个 RAM IP 核内里的复位信号,它并不是低电平有效的,而是高电平有效。而我们的【rw_ram】模块的系统复位信号【sys_rst_n】是低电平有效的。所以呢,为了使连接到 RAM IP 核的异步复位信号能够精确地发挥作用,我们需要将【rw_ram】模块的系统复位信号,【sys_rst_n】,取反以后,再连接到 RAM IP 核内部的【aclr】信号上。
第136行,我们将【rw_ram】模块的系统时钟信号【sys_clk】连接到 RAM IP 核内部的【clock】信号上。
以上两个信号的连接,是系统时钟与系统复位信号与 RAM IP 核的内部信号的连接方法。
对于内存写操纵来说,真正起作用的,是写使能信号【wr_en】,待写数据【data_buf】与地址信号【addr_buf】。我们需要将待写数据【data_buf】的值,写入地址为【addr_buf】的内存单位中。开启写入操纵的机遇是,写使能信号【wr_en】为有效的高电平。
在这里,操纵时序,就起到作用了。我们回首一下,这些个变量,是怎样的时序变革。
当某一个时钟上升沿到临时,如果检测到内部控制信号总线变量的位2为1时,表明控制中央发布了内存写使能信号。这个时间,在非壅闭赋值阶段,将内部地址信号总线变量【addr_sig_inner】的值缓存到【addr_buf】内里,将内部数据信号总线变量【data_sig_inner】的值缓存到【data_buf】内里。
缓存了待写数据与待写地址信号以后,【addr_buf】与【data_buf】又分别在图5的135行与137行,与 RAM IP 核的内部信号连接了起来。而系统时钟与系统复位信号早就连接到 RAM IP 核上了。此时,有了待写数据与待写地址,所差的,就只剩下一个写使能信号了。
我们假定,当系统检测到【ctrl_sig_inner == 1】条件满足的时间,所在的时钟跳变沿,为0号时钟上升沿。根据图2的代码,在0号上升沿之后的非壅闭赋值阶段,【write_time】被非壅闭赋值为1。
然后呢,在1号时钟上升沿的时间,系统会检测到【write_time == 1】条件满足。在1号上升沿之后的非壅闭赋值阶段,根据图3的代码,我们知道,【wr_en】被非壅闭赋值为1。
在2号时钟上升沿的时间,系统会检测到【wr_en == 1】条件满足。2号时钟上升沿使用的时钟信号,为系统时钟信号【sys_clk】。而 RAM IP 核使用的时钟信号,是由系统时钟信号【sys_clk】连接已往的。也就是,RAM IP 核使用的时钟信号,也是系统时钟信号【sys_clk】。
在图5的139行,我们看到,【rw_ram】模块的【wr_en】变量被连接到了 RAM IP 核的【wren】信号上。
【rw_ram】模块与 RAM IP 核使用相同的时钟信号,都使用了系统时钟【sys_clk】的节奏变革。而【rw_ram】模块的【wr_en】信号与  RAM IP 核的【wren】信号相连。这样,当在【rw_ram】模块中,在2号时钟上升沿内里,系统检测到【wr_en】信号为1的时间,此时,在 RAM IP 核内里,也会同时检测到内部的写使能信号【wren】变量为1。
当 RAM IP 核检测到内部的写使能信号为高电平的时间,就根据待写数据【data】与待写地址【address】,进行 ram 写操纵了,将【data】写入【address】地址单位中。
五.    发布完成信号给控制中央

在2号时钟上升沿时,系统会检测到【wr_en】为1,这个时间,RAM IP 核就会开始进行内存写操纵了。正常的话,应该是说,在3号时钟上升沿时,内存写操纵完成。不外,由于内存写操纵,并不需要从 RAM 中接收数据。我们可以在2号时钟上升沿时,向控制中央发布完成信号。
具体地,要怎么来发布呢?
我们先来看一看【write_time_d1】信号。其实,从名字上,大家应该可以猜到,它是一个节拍变量,比【write_time】延后一个时钟周期。我们来看看下面的代码。
   https://i-blog.csdnimg.cn/direct/9faff6d320e342c29616f00849d510f1.png   图6    从图6内里看,【write_time_d1】确实是比【write_time】延后一个时钟周期的节拍变量。
这样的话呢,由于在1号时钟上升沿到来时,系统可以检测到【write_time】为1,所以呢,在2号时钟上升沿到来时,系统就可以检测到【write_time_d1】为1。
反过来,当检测到【write_time_d1】为1的时间,证明此时的时钟跳变沿,为2号时钟上升沿。我们想要在2号时钟上升沿到来以后,给控制中央发布完成信号。我们来看代码。
   https://i-blog.csdnimg.cn/direct/4e904330a6f545c4aa207b39c453cb7f.png   图7    从图7的131行可以看到,【work_ok_inner】的署理变量,为【work_ok_represent】变量。
   https://i-blog.csdnimg.cn/direct/3ecb25e33e38491ea6bf7df34f75c83d.png   图8    对于图8,我们只看红色框线所示的代码。
从图8中的代码可以看到,【rw_ram】模块内部的署理变量【work_ok_represent】在平时,也就是在系统复位与else分支内里,它是被非壅闭赋值为高阻态。而【work_ok_represent】是【rw_ram】模块内部的【work_ok_inner】总线变量的署理。所以呢,在系统复位与闲来无事时,【rw_ram】模块内部的【work_ok_inner】总线变量也是处于高阻态z值,也是与【work_ok_inner】总线处于断开连接的状态。
然后呢,在1号时钟上升沿到来时,也就是检测到【write_time == 1】条件满足之时,通过署理变量【work_ok_represent】向【rw_ram】模块内部的【work_ok_inner】总线变量非壅闭赋值0值。
在2号时钟上升沿到来时,也就是检测到【write_time_d1 == 1】条件满足之时,通过署理变量【work_ok_represent】向【rw_ram】模块内部的【work_ok_inner】总线变量非壅闭赋值1值。
【rw_ram】模块内部的【work_ok_inner】总线变量与【work_ok_inner】总线是相连的,当【rw_ram】模块内部的【work_ok_inner】总线变量被赋值为1时,【work_ok_inner】总线的值也会同时变为1。
【work_ok_inner】总线变为1,控制中央也有这个同名的总线变量,所以呢,控制中央模块是可以接收到这个变为1的【work_ok_inner】总线的值的。所以呢,控制中央就收到了内存写操纵完成的信号了。接下来,控制中央就可以进行其他的操纵了。
需要留意的是,在2号时钟上升沿的非壅闭赋值阶段里,【rw_ram】模块内部的【work_ok_inner】总线变量通过署理变量【work_ok_represent】被非壅闭赋值为1。但是,在2号时钟上升沿到来时,在这个时候,【work_ok_inner】总线上面的值并不是1。
由于是在2号上升沿的非壅闭赋值阶段里,【work_ok_inner】总线变为1值,所以,2号时钟上升沿到来的时候,【work_ok_inner】总线不是1值,而3号时钟上升沿到来的时候,【work_ok_inner】总线却是1值。
然后呢,由于图8的 else 分支的作用,在3号时钟上升沿的非壅闭赋值阶段,【rw_ram】模块内部的【work_ok_inner】总线变量通过署理变量【work_ok_represent】的非壅闭赋值代码,变为高阻态值。此时,【rw_ram】模块的【work_ok_inner】总线变量就与【work_ok_inner】总线断开连接了。
此时,由于【work_ok_inner】总线已经没有任何线路与之连接了,所以,【work_ok_inner】总线也变为了高阻态值。但是呢,这个高阻态z值,会在4号时钟上升沿到来时才被检测到。
竣事语

好了,到了这里,本节的内存写操纵就解说完成了。
下一节,我们来解说内存读操纵。

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