简易CPU设计入门:取指令(三),ip_buf与rd_en的非阻塞赋值
在开篇,还是请大家首先准备好本项目所用的源代码。如果已经下载了,那就不用重复下载了。如果还没有下载,那么,请大家点击下方链接,来了解下载本项目的CPU源代码的方法。
下载本项目代码
准备好了项目源代码以后,我们接着去讲解。
在之前的章节里,我是讲解了,使用Quartus II 13.1的IP核生成的功能,来生成RAM IP核。讲完了这个以后,我们在这一节,接着来讲解取指令模块。
我还是将取指令模块的代码给整体地贴在下面。
module get_instruct
(input wire sys_clk,input wire sys_rst_n,input wire get_inst_en,input wire [15:0] ip,output reg decode_en,output reg [15:0] instruct_code
);reg [15:0] ip_buf;
wire [15:0] instruct_code_wire;reg rd_en;
reg rd_en_d1;
reg rd_en_d2;always @(posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)ip_buf <= 16'h0;else if (get_inst_en == 1'b1)ip_buf <= ip;elseip_buf <= ip_buf;always @(posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)rd_en <= 1'b0;else if (get_inst_en == 1'b1)rd_en <= 1'b1;elserd_en <= 1'b0;always @(posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)beginrd_en_d1 <= 1'b0;rd_en_d2 <= 1'b0;endelsebeginrd_en_d1 <= rd_en;rd_en_d2 <= rd_en_d1;endalways @(posedge sys_clk or negedge sys_rst_n)if (sys_rst_n == 1'b0)begindecode_en <= 1'b0;instruct_code <= 16'h0;endelse if (rd_en_d1 == 1'b1)begindecode_en <= 1'b1;instruct_code <= instruct_code_wire;endelsebegindecode_en <= 1'b0;instruct_code <= instruct_code;endram_disk_256x16 ram_disk_inst (.aclr ( ~sys_rst_n ),.address ( ip_buf ),.clock ( sys_clk ),.data ( 16'hz ),.rden ( rd_en ),.wren ( 1'b0 ),.q ( instruct_code_wire ));endmodule
上述代码块,位于【\cpu_me01\code\get_instruct.v】里面。
一. ip_buf的非阻塞赋值
我们来看看关于ip_buf的非阻塞赋值代码块。
由图1可以看到,ip_buf在复位时,它为0值。检测到输入信号中的【get_inst_en】为高电平以后,ip_buf非阻塞赋值为输入信号【ip】的值。此后,ip_buf保持此值不变。
在这里,取指令使能信号【get_inst_en】,它是来自于控制中心模块【ctrl_center】的。每次准备取指令时,【get_inst_en】才会变为1,且仅仅维持一个时钟周期的高电平。其余的时间里,它为0值。
这样一来,图1中的【ip_buf】,它是说,每检测到一次【get_inst_en】为高电平,就缓存一次【ip】的值,然后在【get_inst_en】为低电平期间,【ip_buf】保持不变。下一次检测到一次【get_inst_en】为高电平的时候,就缓存新的【ip】的值。逻辑不难。
二. rd_en的非阻塞赋值
从图2来看,读使能变量【rd_en】,它在系统复位时,为0值。当检测到控制中心传来的取指令使能信号【get_inst_en】变为高电平的时候,读使能信号【rd_en】变为1。其余时间,【rd_en】为0。
取指令使能我们讲了,它是由控制中心模块传来的,且仅仅维持一个时钟周期的高电平,其余时间为0值。而【rd_en】其实也是一样的。【rd_en】的逻辑,仅仅在检测到【get_inst_en】为1时,【rd_en】才为1,其余时候,【rd_en】为0。而【get_inst_en】仅仅维持一个时钟周期,所以,【rd_en】的高电平也是仅仅维持一个时钟周期。
注意,【ip_buf】与【rd_en】都是本地变量,如下图所示。
图3中的第12行和第15行,可以表明,【ip_buf】与【rd_en】均为本地变量。
三. 延时信号【rd_en_d1】与【rd_en_d2】
在图3中,我们可以看到两个延时信号【rd_en_d1】与【rd_en_d2】。所谓的延时,是对【rd_en】信号进行延时。在这里,虽说我声明了两个延时信号,但是,实际用到的,只有【rd_en_d1】而已。之所以要多申请一个,是因为,我担心一个延时信号不够用。
生活中,好多事情我也是这样的。因为总担心东西会不够用,所以我倾向于多准备一些。对于擅长精打细算的人来讲,我这种做法,可能会显得有些不好理解。
我们还是来看一看代码。
我先来说一说代码的执行效果。效果就是,【rd_en_d1】相比【rd_en】延后了1个时钟周期,【rd_en_d2】又比【rd_en_d1】延后了1个时钟周期。
接下来,我又会用文字说明的方法,来演示这种代码执行过程了。请大家先将图4给保存好,以随时对照着我的文字讲解。
我们知道,【rd_en】变为1,是由于非阻塞赋值。那么,它肯定是在某一个时钟上升沿到来后,在非阻塞赋值的第2阶段变为1的。
那么,我们先将初始条件设置为,时钟周期处于【rd_en】变为1的之前的一个时钟周期。
【初始条件】假定某一个时钟上升沿到来时,rd_en == 0,且本周期里面 rd_en 不会变为1。我们将这个时钟上升沿,定义为0号上升沿。此时,rd_en_d1与rd_en_d2的值均为0。
在0号时钟上升沿到来后的非阻塞赋值第1阶段,计算非阻塞赋值的右侧表达式的值。这个时候,表达式【rd_en_d1 <= rd_en】与表达式【rd_en_d2 <= rd_en_d1】的右侧表达式分别为【rd_en】与【rd_en_d1】,它们都为0。
在0号时钟上升沿到来后的非阻塞赋值第2阶段,将右侧表达式的值赋予左侧的变量。这样一来,在这个阶段里,rd_en_d1与rd_en_d2的值均被赋值为0,与0号时钟上升沿到来时的值是一样的。
【1号时钟上升沿到来】此时rd_en为0,且假定本上升沿到来后的非阻塞赋值第2阶段里,rd_en被非阻塞赋值为1。此时,rd_en_d1与rd_en_d2的值依然为0。
在1号上升沿到来后的非阻塞赋值第1阶段,计算非阻塞赋值的右侧表达式的值。此时,右侧表达式【rd_en】与【rd_en_d1】的值均为0。
在1号时钟上升沿到来后的非阻塞赋值第2阶段,将右侧表达式的值赋予左侧的变量。这样一来,在这个阶段里,rd_en_d1与rd_en_d2的值均被赋值为0,与1号时钟上升沿到来时的值是一样的。
【2号时钟上升沿到来】此时rd_en为1,且本上升沿到来后的非阻塞赋值第2阶段里,rd_en被非阻塞赋值为0。此时,rd_en_d1 == 0,rd_en_d2 == 0。
在2号上升沿到来后的非阻塞赋值第1阶段,计算非阻塞赋值的右侧表达式的值。此时,右侧表达式【rd_en】的值为1,右测表达式【rd_en_d1】的值为0。
在2号上升沿到来后的非阻塞赋值第2阶段,将右侧表达式的值赋予左侧的变量。这样一来,rd_en_d1被赋值为1,rd_en_d2被赋值为0。也就是,rd_en_d1变为1,而rd_en_d2不变。
【3号时钟上升沿到来】此时,rd_en == 0,rd_en_d1 == 1, rd_en_d2 == 0。
在3号上升沿到来后的非阻塞赋值第1阶段,计算非阻塞赋值的右侧表达式的值。此时,右侧表达式【rd_en】的值为0,【rd_en_d1】的值为1。
在3号上升沿到来后的非阻塞赋值第2阶段,将右侧表达式的值赋予左侧的变量。这样一来,rd_en_d1被赋值为0,rd_en_d2被赋值为1。
【4号时钟上升沿到来】此时,rd_en == 0,rd_en_d1 == 0, rd_en_d2 == 1。
在4号上升沿到来后的非阻塞赋值第1阶段,计算非阻塞赋值的右侧表达式的值。此时,右侧表达式
【rd_en】的值为0,【rd_en_d1】的值为0。
在4号上升沿到来后的非阻塞赋值第2阶段,将右侧表达式的值赋予左侧的变量。这样一来,rd_en_d1被赋值为0,rd_en_d2被赋值为0。
我们将上面的几个文字说明的信息摘录一下,我们将【rd_en】,【rd_en_d1】与【rd_en_d2】变为1的时机给摘录下来。
在1号时钟上升沿到来后,在非阻塞赋值的第2阶段,rd_en被非阻塞赋值为1。
在2号时钟上升沿到来后,在非阻塞赋值的第2阶段,rd_en_d1被非阻塞赋值为1。
在3号时钟上升沿到来后,在非阻塞赋值的第2阶段,rd_en_d2被非阻塞赋值为1。
所以呢,rd_en,rd_en_d1,rd_en_d2,它们分别是右边的信号比左边的信号延后一个时钟周期变为1。
四. 延时例题
本文第三节主要是为了向大家讲述延时逻辑。那个具体的文字表述不是重点,重点时,再次出现延时逻辑,你得是能够明白。
下面,我给大家来一个例题。
如果第3节的知识,大家看懂了,那么,图5中的代码,其实是不难的。
图5中的代码,依然是一个延时逻辑。
signal,signal_d1,signal_d2,signal_d3,signal_d4,signal_d5,signal_d6,这几个信号,分别是右边的信号比左边的信号延后一个时钟周期。
延时逻辑,大家明白了没?
结束语
在本节,我又水了一节。
延时逻辑,也算是一个有趣的硬件代码逻辑。希望大家能学会。
本节里面,我没有采用表格的方法来解读代码逻辑,而是采用了文字说明的方法。其实两种方法只是不同的方法而已。你可以选择一种方法,来研究你所关注的问题。
表格的话,其实我还是比较推荐大家去使用它。图表,应该算是现代社会里,我们经常需要去观察和分析的材料吧。
会计里面有资产负债表,炒股的人也需要去看股票价格的走势图。信息时代,图表思维,大概也是我们需要去训练的一种思维了。
本节结束。
相关文章:
简易CPU设计入门:取指令(三),ip_buf与rd_en的非阻塞赋值
在开篇,还是请大家首先准备好本项目所用的源代码。如果已经下载了,那就不用重复下载了。如果还没有下载,那么,请大家点击下方链接,来了解下载本项目的CPU源代码的方法。 下载本项目代码 准备好了项目源代码以后&…...
【算法】---归并排序(递归非递归实现)
参考 左程云算法 算法导论 前言 本篇介绍 归并排序分治法 前置知识 了解递归, 了解数组。 引入 归并排序 归并排序最早是由公认的现代计算机之父John von Neumann发明的, 这是一种典型的分治思想应用。 我们先介绍分治思想 分治思想 分治思想的…...
UniVue大版本更新:UniVue2.0.0-preview
大版本发布说明 距离上次更新好像已经过去很久了,最近太忙了没时间维护新版本,也是自己在使用的过程中发现了很多问题也有了更多的灵感,由于和之前的版本区别太大,决定重新开一个大版本。这个UniVue2之后的版本追求是性能…...
RabbbitMQ篇(环境搭建 - 下载 安装)(持续更新迭代)
目录 一、Windows 1. 下载安装程序 2. 安装配置erlang 3. 安装rabbitMQ 4. 验证 二、Linux 1. 下载rpm包 1.1. 下载Erlang的rpm包 1.2. 下载socat的rpm包 1.3. 下载RabbitMQ的rpm包 2. 安装 2.1. 安装Erlang 2.2. 安装socat 2.3. 安装RabbitMQ 3. 启动RabbitMQ服…...
C++基础补充(02)C++其他控制语句break continue goto等
文章目录 1. break2. continue 语句3. goto 语句goto的存在 4. 跳出多重循环4.1 goto 直接跳转4.2 C11及其后版本的 return 语句4.3 使用标志变量 在C中,控制语句用于管理程序的执行流程。常见有 break、continue 和 goto。 1. break break语句主要用于在循环或者s…...
决策树中联合概率分布公式解释说明
学习决策树时书本中有一公式 7-3 是: P ( X x i , Y y j ) p i j ( i 1 , 2 , … , m , j 1 , 2 , … , n ) P(X x_i, Y y_j) p_{ij} \quad (i 1, 2, \dots, m, \ j 1, 2, \dots, n) P(Xxi,Yyj)pij(i1,2,…,m, j1,2,…,n) 这个公式表示的是随机变…...
计算机毕业设计 农场投入品运营管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…...
php email功能实现:详细步骤与配置技巧?
php email发送功能详细教程?如何使用php email服务? 无论是用户注册、密码重置,还是订单确认,电子邮件都是与用户沟通的重要手段。AokSend将详细介绍如何实现php email功能,并提供一些配置技巧,帮助你更好…...
MapBox Android版开发 6 关于Logo
MapBox Android版开发 6 关于Logo Logo的显示查看源码及思路(Logo)第一步第二步 隐藏Logo示例查看源码及思路(Info)第一步第二步 隐藏Logo和Info示例 看到有网友留言问如何移除Logo,今天看了下V9源码,发现M…...
2024年房市
24年8月15日,国家统计局公布,“7月末,商品房待售面积73926万平方米”。(原文链接:https://www.stats.gov.cn/sj/zxfb/202408/t20240815_1955982.html) 7.39亿平方存量商品房,估价均价1万每平,总价约&am…...
index索引
index索引: create index 【1】on 【2】(【3】) 1为索引名,通常为id_表名_列名。2为表名。3为列名。 CREATE INDEX id_account_id ON account(id); -- 根据id创建索引 CREATE INDEX id_account_idname on account(id,name); -- 创建组合索引 索…...
理解互联网链路:从本地ISP到Tier 1 ISP运营商
1. 互联网服务提供商(ISP) 互联网服务提供商(ISP)是指提供互联网接入服务的公司或组织。它们负责将用户连接到互联网,并提供相关的服务,如电子邮件、网站托管和其他在线服务。ISP可以分为不同的层级&#…...
基于元神操作系统实现NTFS文件操作(三)
1. 背景 本文主要介绍DBR的读取和解析,并提供了基于元神操作系统的实现代码。由于解析DBR的目的是定位到NTFS磁盘分区的元文件$Root进行文件操作,所以只解析了少量的部分,其它部分可以参考相关文档进行理解。 DBR存在于磁盘分区的第一个扇区…...
深度学习与数学归纳法
最近发现,深度学习可以分为两个主要的阶段,分别是前向推理以及反向传播,分别对应着网络的推理和参数训练两个步骤。其中推理有时候也称为归纳推理。 在做参数训练的时候,本质上是在利用历史数据求网络参数的先验分布; …...
《Linux从小白到高手》理论篇(六):Linux软件安装一篇通
List item 本篇介绍Linux软件安装相关的操作命令,看完本文,有关Linux软件安装相关操作的常用命令你就掌握了99%了。 Linux软件安装 RPM RPM软件的安装、删除、更新只有root权限才能使用;查询功能任何用户都可以操作;如果普通用…...
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
1. 运行项目 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Appl…...
②EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器
EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器https://item.taobao.com/item.htm?ftt&id798036415719 EtherCAT 串口网关 EtherCAT 转 RS485 (接上一章) 自由协议通信步骤 (以MS-A2-1041为例) 接收与…...
matlab-对比两张图片的HSV分量的差值并形成直方图
%对比两张图片的HSV分量的差值并形成直方图,改个路径就能用,图片分辨率要一致 close all; clear all; clc; I1imread(E:\test\resources\image\1.jpg); I2imread(E:\test\resources\image\2.jpg); HSV1 rgb2ntsc(I1); HSV2 rgb2ntsc(I2); %HSV,HSV 代…...
微服务SpringGateway解析部署使用全流程
官网地址: Spring Cloud Gateway 目录 1、SpringGateway简介 1、什么是网关 2、为什么用网关【为了转发】 2、应用: 1.启动nacos 2.创建网关项目 3.网关配置1 4.网关配置2【了解】 5.过滤器配置【了解】 1、SpringGateway简介 核心功能有三个&…...
Solidity 存储和内存管理:深入理解与高效优化
在 Solidity 中,存储和内存管理是编写高效智能合约的关键组成部分。合约执行的每一步操作都可能涉及到数据的存储和读取,而这些操作对 gas 的消耗有很大影响。因此,理解 Solidity 的存储模型以及如何优化数据的管理对于合约的安全性、性能和成…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
