简易CPU设计入门:内存读写(二)

项目代码下载

请大家首先准备好本项目所用的源代码。如果已经下载了,那就不用重复下载了。如果还没有下载,那么,请大家点击下方链接,来了解下载本项目的CPU源代码的方法。

CSDN文章:下载本项目代码

上述链接为本项目所依据的版本。

在讲解过程中,我还时不时地发现自己在讲解与注释上的一些个错误。有时,我还会添加一点新的资料。在这里,我将动态更新的代码版本发在下面的链接中。

Gitee项目:简易CPU设计入门项目代码:

讲课的时候,我主要依据的是CSDN文章链接。然后呢,如果你为了获得我的最近更新的版本,那就请在Gitee项目链接里下载代码。

准备好了项目源代码以后,我们接着去讲解。

本节前言

在上一节,我是讲解了【rw_ram】模块的端口声明与变量声明的部分。本节,我来将内存写操作。

本节的代码,主要位于【...cpu_me01\code\Ctrl_Center\】路径里面,所所涉及的代码文件,主要是【rw_ram.v】和【ctrl_center.v】。

一.    内部控制信号

图1,控制中心模块的注释代码
/*********************************************
ctrl_sig_inner[0]:register write enable:寄存器写使能
ctrl_sig_inner[1]:register read enable:寄存器读使能
ctrl_sig_inner[2]:random memory write ebable:内存写使能
ctrl_sig_inner[3]:random memory read enable:内存读使能
ctrl_sig_inner[4]:Arithmetic and Logic calculate:算术逻辑运算
ctrl_sig_inner[5]:reserve:保留
ctrl_sig_inner[6]:reserve:保留
ctrl_sig_inner[7]:reserve:保留
ctrl_sig_inner[8]:reserve:保留
ctrl_sig_inner[9]:reserve:保留
ctrl_sig_inner[10]:reserve:保留
ctrl_sig_inner[11]:reserve:保留
ctrl_sig_inner[12]:reserve:保留
ctrl_sig_inner[13]:reserve:保留
ctrl_sig_inner[14]:reserve:保留
ctrl_sig_inner[15]:reserve:保留
还有一种运算叫做读取立即数,将立即数放入内部寄存器。
此运算不需要通过内部信号的参与。
************************************************/

在图1中,我们着重看40行的代码。它的意思是说,当内部控制信号总线的位2为1,其它位都是0的时候,它代表的是,控制中心发布了内存写使能信号。

接下来呢,我们来看一看。当检测到有效的内存写使能信号以后,都有哪些变化。

二.       write_time 与 wr_en

图2,内存读写模块的代码

从图2可以看到,write_time属于是这样的一种类型的变量。平时的时候,它是0值。只有在满足特定的条件的时候,它才变为高电平。

这个特定的条件,就是内部控制信号总线【ctrl_sig_inner】的位2为1。

当内部控制信号总线【ctrl_sig_inner】的位2为1时,代表着,控制中心发布了内存写使能信号。这个内部控制总线上的内存写使能信号仅仅是维持一个时钟周期,随后,内部控制总线将会处于高阻态状态。

所以呢,在这里,【write_time】维持高电平状态的时间,也是只有一个时钟周期。其余时间,它都是0值。

我们再来看一看【wr_en】的逻辑。

图3

从图3可以看出,【wr_en】的逻辑是,当检测到【write_time】为1的时候,【wr_en】被非阻塞赋值为1,其余时间,为0值。

由于write_time仅维持一个时钟周期的高电平,所以呢,【wr_en】的高电平时间,也仅仅维持一个时钟周期。

三.    内部地址信号与内部数据信号的缓存

图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 核的实例化代码

图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[2] == 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】延后一个时钟周期。我们来看看下面的代码。

图6

从图6里面看,【write_time_d1】确实是比【write_time】延后一个时钟周期的节拍变量。

这样的话呢,由于在1号时钟上升沿到来时,系统可以检测到【write_time】为1,所以呢,在2号时钟上升沿到来时,系统就可以检测到【write_time_d1】为1。

反过来,当检测到【write_time_d1】为1的时候,证明此时的时钟跳变沿,为2号时钟上升沿。我们想要在2号时钟上升沿到来以后,给控制中心发布完成信号。我们来看代码。

图7

从图7的131行可以看到,【work_ok_inner】的代理变量,为【work_ok_represent】变量。

图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号时钟上升沿到来时才被检测到。

结束语

好了,到了这里,本节的内存写操作就讲解完成了。

下一节,我们来讲解内存读操作。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS 学习之 padding 与图形绘制

padding 属性和 background-clip 属性配合,可以在有限的标签下实现一些 CSS 图形绘制效果,我这里举两个小例子,重在展示可行性。 例 1:不使用伪元素,仅一层标签实现大队长的“三道杠”分类图标效果。此效果在移动端比较常见&…

Qt实现使用TCP与RS485串口设备通信————附带详细实践方法

文章目录 0 背景1 协议介绍1.1 modbusRTU协议1.1.1 简介1.1.2 RS485和modbusRTU的关系1.1.3 modbusRTU 协议格式1.1.3.1 0x10写多个保持寄存器1.1.3.2 0x02读多个离散输入寄存器1.1.3.3 0x03读多个保持寄存器1.1.3.4 0x04读多个输入寄存器 1.2 ModbusTCP协议1.2.1 ModbusTCP协议…

Mono里运行C#脚本21—mono_image_init_name_cache

前面分析了怎么样加载mscorlib.dll文件,然后把文件数据读取到内存。 接着下来,就会遇到加载整个C#的类型系统,比如System. Object,大体类型如下图所示: 在对CIL编译之前,需要把这些类型全部加载到内存里,以便快捷地访问它们。 mono_image_init_name_cache函数就是完成…

Linux(14)——网络管理

目录 一、检测网络配置: 1、查看网络接口(ip): 2、查看性能(ip): 3、查看 IP 地址(ip): 4、查看路由表(ip): 5、追踪…

深度学习笔记(12)——深度学习概论

深度学习概论 深度学习关系: 为什么机器人有一部分不在人工智能里面:机器人技术是一个跨学科的领域,它结合了机械工程、电子工程、计算机科学以及人工智能(AI)等多个领域的知识。 并不是所有的机器人都依赖于人工智能…

基于Springboot + vue实现的高校办公室行政事务管理系统

🥂(❁◡❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞 💖📕🎉🔥 支持我:点赞👍收藏⭐️留言📝欢迎留言讨论 🔥🔥&…

欧科云链研究院:ChatGPT 眼中的 Web3

编辑|OKG Research 转眼间,2024年已经进入尾声,Web3 行业经历了热闹非凡的一年。今年注定也是属于AI的重要一年,OKG Research 决定拉上 ChatGPT 这位“最懂归纳的AI拍档”,尝试把一整年的研究内容浓缩成精华。我们一共…

急需升级,D-Link 路由器漏洞被僵尸网络广泛用于 DDoS 攻击

僵尸网络活动增加 :新的“FICORA”和“CAPSAICIN”僵尸网络(Mirai 和 Kaiten 的变体)的活动激增。 被利用的漏洞 :攻击者利用已知的 D-Link 路由器漏洞(例如 CVE-2015-2051、CVE-2024-33112)来执行恶意命…

df.replace({‘b‘: r‘\s*(\.)\s*‘}, {‘b‘: r‘\1ty‘}, regex=True)

这段代码 df.replace({b: r\s*(\.)\s*}, {b: r\1ty}, regexTrue) 用于在 DataFrame 中进行替换操作,具体来说是针对 b 列,匹配并替换符合正则表达式的值。 详细解析: df.replace():这是 Pandas 中的 replace() 方法,用…

springboot原生socket通讯教程

需求背景 最近需要对接一些硬件设备,他们选择了socket通讯,并且使用的是私有化协议加密通讯。这种情况下适合原生的socket加解密解析,不适合NettySocket,这在开发中增加了难度。所有的代码都要手动去敲。如果你的只想通过socket传输一些数据,而且都是json的数据,例如聊天…

redis的学习(一)

1.环境搭建 1.1 在ubuntu上安装redis 1.2 reids客户端介绍 redis也是一个客户端-服务器结构的程序。redis客户端和服务器可以在同一份主机上,也可以在不同的主机上,因为二者是通过网络进行发送和接收请求的。 redis服务器是负责存储和管理数据的。 red…

UCAS 24秋网络认证技术 CH16 OAuth OIDC复习

单点登录、OAuth、OIDC原理过程区别 文章目录 单点登录、OAuth、OIDC原理过程区别单点登录概念优点 什么是 OAuth?概述OAuth 2.0 中的角色客户端类型客户端注册抽象协议流程协议流程图 Authorization Grant (授权许可)Access Token (访问令牌)Refresh Token (刷新令…

PDF预览插件

PDF预览插件 可用于当前页面弹窗形式查看,可增加一些自定义功能 pdf预览插件 代码块: pdfobject.js <div class="pdfwrap"><div class="item"><h3>笑场</h3><div class="tags"><p>李诞</p><i&…

Echarts+vue电商平台数据可视化——webSocket改造项目

websocket的基本使用&#xff0c;用于测试前端能否正常获取到后台数据 后台代码编写&#xff1a; const path require("path"); const fileUtils require("../utils/file_utils"); const WebSocket require("ws"); // 创建WebSocket服务端的…

Transformer从零详细解读——DASOU讲AI

1. 从全局角度概括Transformer transformer的任务是什么&#xff1f; 进一步细化 进一步细化&#xff0c;注意&#xff1a;每个encoder结构相同&#xff0c;参数不同&#xff1b;decoder同理 原论文中的图如下&#xff1a; 2.Encoder 2.1 输入部分 &#xff08;1&#xff09…

696: Soldiers

曼哈顿距离&#xff08;Manhattan Distance&#xff09; 在二维空间中&#xff0c;两个点 (x1, y1) 和 (x2, y2) 的 曼哈顿距离 是&#xff1a; |x1 - x2| |y1 - y2| 曼哈顿距离描述了在网格上行走的距离&#xff0c;限制只能水平或垂直移动。 #include <iostream>…

自学记录鸿蒙API 13:实现多目标识别Object Detection

起步&#xff1a;什么叫多目标识别&#xff1f; 无论是生活中的动物识别、智能相册中的场景分类&#xff0c;还是工业领域的检测任务&#xff0c;都能看到多目标识别的身影。这次&#xff0c;我决定通过学习HarmonyOS最新的Object Detection API&#xff08;API 13&#xff09…

【Cesium】九、Cesium点击地图获取点击位置的坐标,并在地图上添加图标

文章目录 一、前言二、实现方法三、App.vue 一、前言 查找发现好几种方法可以获取到点击位置的坐标。这里我实现需求就不深究学习了。将几位大佬的方法学习过来稍微整合了一下。 本文参考文章&#xff1a; cesium 4种拾取坐标的方法 【Cesium基础学习】拾取坐标 cesium拾取当…

ts总结一下

ts基础应用 /*** 泛型工具类型*/ interface IProps {id: string;title: string;children: number[]; } type omita Omit<IProps, id | title>; const omitaA: omita {children: [1] }; type picka Pick<IProps, id | title>; const pickaA: picka {id: ,title…

人脑处理信息的速度与效率:超越计算机的直观判断能力

人脑处理信息的速度与效率&#xff1a;超越计算机的直观判断能力 关键词&#xff1a; #人脑信息处理 Human Brain Information Processing #并行处理 Parallel Processing #视觉信息分析 Visual Information Analysis #决策速度 Decision Speed #计算机与人脑比较 Computer v…