11.1~11.2双端口RAM(报错复盘,一些理解(循环,阻塞非阻塞),三目运算符解决使能端)

双端口RAM

分别用于读写数据,同时进行

当读使能端有效时可以读出来数据

当写使能端有效时可以覆写数据

读写并行操作

报错

1.reg必须在always里

这个不能assign,因为reg型不能assign,单端口的那个可以assign是因为其定义为了wire型,就不在always里进行,而是在运算后输出时用的,所以可以assign

这里定义成了reg,那么赋值就一定要写在always里

2.多个else if的操作覆盖

这个不能得到正确输出是因为,一个if里只能执行一次,即即使有多个else if,且都满足,也只进行一个判别条件里的(靠近顶层的),就是说如果读写信号都有效,也只会进行写操作,而屏蔽掉读操作,所以就会出问题,导致一直读不出来

解决方式就是把读和写分在两个always里,保证不会因为else if只会执行一个,而使另一个被屏蔽掉

3.未知情况的完善缺陷

只是这样依然会得不到期望的输出,2的情况是一直读不出来,即输出信号一直是0

3的情况是,由于没有对读使能端情况的完善,即只在读为1时,才会对输出信号做出修改,但是却没有说读为0时该怎么做,就会导致,在读为0时,锁存上一个读为1时读到的信号,这样就会导致在不想读时,一直输出有信号的读信号,就会出错,得不到预期的波形

解决方法就是完善各种使能端的情况,当读使能端为0时,就要把读的输出信号置0

对于写使能,写的功能就是改变RAM内部数据值

当为1时,进行覆写;为0时,保持原状态(可写可不写,但必须明白这种情况的处理是这样的);

对于读使能,功能就是改变读信号,读出信号

当为1时,进行读;为0时,显然不希望之前的信号依然保存,所以要进行置0操作(这时就必须要额外写)

补充:对于2的另一种解决方法

还是在一个always里,只不过不用else if了,就用if,保证每次都会对if里的条件进行判断,简便,但是在互斥事件时,会浪费一定的不必要的判定时间,但是对独立的事件,就是必要的

其他

本例中的阻塞与非阻塞

这里面用阻塞赋值,即=可行,是因为状态的转移不涉及上一个状态,所以可以直接改变

而读写时,也是可以直接读出想写的内容,而不是之前写的内容,即读写和原来写的是什么无关

关于循环

要用循环,就要定义integer量,integer不能综合,只是用来循环,简化代码

这里的循环就是用来初始化,简化代码用的,无法综合,因为没有元件符合,只是用来简化代码长度而诞生的,初始化的本质逻辑还是逐个赋0,即

如果有128个寄存器,就需要128行,而循环无所谓深度多少

另一种实现思路

由于使能端只能是0或1,所以用三目运算符可以简单清晰,明了的表示出各种情况及方法,不重不漏。

读写分离always,两个三目运算符考虑两个使能端的各种情况

同步FIFO

就是说读使能时,返回队头;不读,则返回0;

写使能时,如果不满,就接着写,满了,就让队头出,写在队尾;不写,保持原态;

空信号,是读的时候空,对写没影响,即往后写,但是改变读的结果,为0;

满信号,是写的时候满,对读没影响,即一直读队头,但是改变写的模式;

但是注意,这里的读出,就是取出队列,即读一个取一个;

根据双口RAM实现FIFO

双端口实现

深度即寄存器数量,位宽为WIDTH

对组地址信号的位宽,为深度对2取对数,向上取整

电路功能

FIFO

空满状态的判断

统计队列内部数据数量的计数器CNT,并根据计数器的大小判断空满状况。

如果CNT==0,则空,如果CNT==深度,则满

读写同时进行时,计数器数值不变;写入时,CNT+1;读出时,CNT-1;

这里是声明读写地址,以及队列深度的计数(采用二进制)

关于位宽

常见的两种含义,第一种的位宽用于数据结构的定义,第二种用于数据结构内部数据特性、大小的定义

一是位宽代表个数

即有多少位宽,就意味有几个数据

队列定义,寄存器堆定义,数组定义,都是这个意思,即[n-1:0],从0拉到n-1,表示这个数据结构里有n个数据,一位就代表了一个数据单元

用来统筹管理数据的记录情况

二是代表实际大小

即用于实际计数,内部存储超过2的数据,表示数据,存储大的数据都是这种方式,位宽越大,表示这个数据越大,就代表一个实际的、实在的数据,采用的二进制计数,位宽就是用的几位二进制来记录

地址信号的定义,队列长度计数,分频器信号的计数,都是这个意思,其都是代表的一个数据

读写地址的确定

写功能,得到写的地址,

首先要写使能为1,接着判断是否满了,如果满了,地址就不动了,即指向队尾;不满,就让地址往后+1

读功能,得到读取元素的地址

首先要读使能为1,接着判断是不是为空,为空,则输出'0,即当前队列没有元素可以读出来;不为空,则地址往后+1,表示当前这个地址已经读出来了

注意,这里就是一定要用非阻塞赋值了,即等到这个电路功能都实现了再变化

因为此时后续的操作,都需要当前指针(即此时的waddr,raddr)所指向的地址,如果这时候更新,就访问不到了,所以需要在都结束后再更新

当前队列长度的确定

这个就是只取一个else if,即同一状态向后的不同分支,只取一个

当又读又写的时候,长度不变

读的时候,长度减1;写的时候,长度+1;

未知情况,保持不变

满空判断

实例化,以双端RAM实现FIFO

需要注意,如果能写而且还没满,就可以实际接着往下写,但是如果能写但是已经满了,就不接着往后写了;读也是这样

想的是,先一直写,然后读,这时候队列长度就减小了,还可以接着往里面写,但是写指针却没有动,所以就会导致越界

一种可能的思路是,它要读就一直读,直到读到空;要写就一直写,直到写到满;

主要就是读的时候,如果读,就一直读,全部读完,而不是读一部分,使其有剩余

那么FIFO的使用方式就是
`timescale 1ns/1ns
/**********************************RAM************************************/
module dual_port_RAM #(parameter DEPTH = 16,
					   parameter WIDTH = 8)(
	 input wclk
	,input wenc
	,input [$clog2(DEPTH)-1:0] waddr  //深度对2取对数,得到地址的位宽。
	,input [WIDTH-1:0] wdata      	//数据写入
	,input rclk
	,input renc
	,input [$clog2(DEPTH)-1:0] raddr  //深度对2取对数,得到地址的位宽。
	,output reg [WIDTH-1:0] rdata 		//数据输出
);

reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];

always @(posedge wclk) begin
	if(wenc)
		RAM_MEM[waddr] <= wdata;
end 

always @(posedge rclk) begin
	if(renc)
		rdata <= RAM_MEM[raddr];
end 

endmodule  

/**********************************SFIFO************************************/
module sfifo#(
	parameter	WIDTH = 8,
	parameter 	DEPTH = 16
)(
	input 					clk		, 
	input 					rst_n	,
	input 					winc	,
	input 			 		rinc	,
	input 		[WIDTH-1:0]	wdata	,

	output reg				wfull	,
	output reg				rempty	,
	output wire [WIDTH-1:0]	rdata
);
    wire                    wenc;
    reg [$clog2(DEPTH) : 0] waddr;
    reg [$clog2(DEPTH) : 0] raddr;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            wfull <= 'd0;
            rempty <= 'd0;
        end
        else begin
            wfull <= waddr == raddr + DEPTH;
            rempty <= waddr == raddr;
        end
    end
    
    assign wenc = winc && !wfull;
    assign renc = rinc && !rempty;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) 
            waddr <= 'd0;
        else if (wenc)
            waddr <= waddr + 'd1;
    end
    
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) 
            raddr <= 'd0;
        else if (renc)
            raddr <= raddr + 'd1;
    end
    
    
    dual_port_RAM #(.DEPTH (DEPTH),
                    .WIDTH (WIDTH))
    dual_port_RAM (
        .wclk  (clk  ),
        .wenc  (wenc ),
        .waddr (waddr),
        .wdata (wdata),
        .rclk  (clk  ),
        .renc  (renc ),
        .raddr (raddr),
        .rdata (rdata)
    );

endmodule

输入信号里有时钟信号,复位信号,读写使能信号,输入信号,

输出信号里有满信号,空信号,输出的队头信号

输入的时候,就写使能打开,然后

同步FIFO是说读写的时钟是一致的

异步FIFO

第一部分是双口RAM,用于数据的存储

第二部分是数据写入控制器

第三部分是数据读取控制器

第四部分是读指针同步器

使用写时钟的两级触发器采集读指针,输出到数据写入控制其

第五部分是写指针同步器

比较空满,采用格雷码的比较来产生

格雷码是循环编码,

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

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

相关文章

Cgroups定义及验证

sudo lsb_release -a可以看到操作系统版本是20.04&#xff0c;sudo uname -r可以看到内核版本是5.4.0-156-generic。 Linux Cgroups 的全称是 Linux Control Group。它最主要的作用&#xff0c;就是限制一个进程组能够使用的资源上限&#xff0c;包括 CPU、内存、磁盘、网络带…

Vector CANape 21安装

系列文章目录 文章目录 系列文章目录简介下载 Vector CANape 21 简介 CANape基础操作介绍&#xff1a;工程创建&#xff0c;测量&#xff0c;标定&#xff0c;离线分析操作。 下载 Vector CANape 21 如下是Vector CANape21的下载安装步骤&#xff1a; https://www.vector.co…

题号1575 C.难度排名 (并查集知识点)

题目&#xff1a; 样例1&#xff1a; 输入 1 4 3 1 4 2 4 3 4 输出 No 样例2&#xff1a; 输入 1 4 2 1 3 2 3 输出 Yes 思路&#xff1a; 这题&#xff0c;有两种情况是由矛盾的。 第一种情况&#xff1a;当前题号存在大于两个题号的相连&#xff0c;情况是矛盾的&#x…

关于微软文本转语音(语音合成)的一些坑

1. 单个音频时长限制10分钟 文档地址 2. 多人配音SSML 每次请求 <voice> 标签只能最大50个&#xff0c;参考 #1 3. SDK 在 linux 环境下 报错&#xff1a;gcc 软件无法加载 4. 语音品质问题 使用 SDK 生成的音频声音很差&#xff0c;默认音频流格式为 WAV&#xf…

Android 复杂UI界面分模块解耦的一次实践

一、复杂UI页面开发的问题 常见的比较复杂的UI界面&#xff0c;比如电商首页&#xff0c;我们看看某电商的首页部分UI&#xff1a; 上面是截取的首页部分&#xff0c;如果这个首页如果不分模块开发会遇到哪些问题&#xff1f; 开发任务不方便分割&#xff0c;一个人开发的话周…

【UE5 Cesium】actor随着视角远近来变化其本身大小

效果 步骤 1. 首先我将“DynamicPawn”设置为默认的pawn类 2. 新建一个父类为actor的蓝图&#xff0c;添加一个静态网格体组件 当事件开始运行后添加一个定时器&#xff0c;委托给一个自定义事件&#xff0c;每2s执行一次&#xff0c;该事件每2s获取一下“DynamicPawn”和acto…

《算法通关村—如何使用中序和后序来恢复一颗二叉树》

《算法通关村—如何使用中序和后序来恢复一颗二叉树》 中序&#xff1a;3 4 8 6 7 5 2 1 10 9 11 15 13 14 12 后序&#xff1a;8 7 6 5 4 3 2 10 15 14 13 12 11 9 1 通过后续遍历我们知道根节点是1&#xff0c;通过知道根节点是1&#xff0c;我们就可以从中序序列知道那些 …

材质之选:找到适合你的地毯

当谈到家居装饰时&#xff0c;地毯是一个经常被忽视的重要元素。但事实上&#xff0c;地毯在家居中扮演了至关重要的角色&#xff0c;不仅可以增加舒适感&#xff0c;还可以改善室内的整体氛围。在这篇文章中&#xff0c;我们将探讨地毯的选择、尺寸、形状和材质&#xff0c;以…

0基础学习PyFlink——使用DataStream进行字数统计

大纲 sourceMapSplittingMapping ReduceKeyingReducing 完整代码结构参考资料 在《0基础学习PyFlink——模拟Hadoop流程》一文中&#xff0c;我们看到Hadoop在处理大数据时的MapReduce过程。 本节介绍的DataStream API&#xff0c;则使用了类似的结构。 source 为了方便&…

使用 Docker 搭建一个“一主一从”的 MySQL 读写分离集群(超详细步骤)

目录 一、前提二、MySQL 生产安装1&#xff0c;拉取mysql2&#xff0c;查看mysql镜像3&#xff0c; 启动 mysql 容器4&#xff0c;修改mysql的中文编码5&#xff0c;查看验证mysql的中文编码 三、Mysql主机 mysql_master 的安装与配置1&#xff0c; 拷贝master容器2&#xff0c…

stable-diffusion 电商领域prompt测评集合

和GhostReivew一个思路&#xff0c;还是从比较好的图片或者是civitai上找一些热门的prompt&#xff0c;从小红书上也找到了不少的prompt&#xff0c;lexica.art上也有不少&#xff0c;主要是为了电商场景的一些测评&#xff1a; 小红书、civitai、Lexica、Liblib.ai、 depth o…

在钣金加工领域,迅镭激光切割机广泛使用的原因和优点何在?

激光切割工艺和激光切割设备正在被广泛的板材加工企业逐渐理解并接受&#xff0c;凭借其高效率的加工、高精度的加工、优质的切割断面、三维切割能力等诸多优势&#xff0c;逐步取代了传统的钣金切割设备。 苏州迅镭激光科技有限公司推出的激光切割设备的柔性化程度高&#xff…

降低边际成本:跨境电商的利润增长策略

在竞争激烈的跨境电商领域&#xff0c;降低成本是提高利润的关键。边际成本&#xff0c;即生产或销售一件额外商品所需的额外成本&#xff0c;在跨境电商中起到至关重要的作用。在本文中&#xff0c;我们将探讨降低边际成本的策略&#xff0c;以实现跨境电商的利润增长。 供应链…

centos7中实现多个python版本共存(python2.7、python3.6、python3.9等)

问题描述&#xff1a; 开发环境中&#xff0c;新项目需要在python3.9及以上版本开发&#xff0c;为了不影响之前运行在python3.6上的项目&#xff0c;就需要增加一个python3.9环境。线上直接使用docker部署就可以了。 解决办法 前提&#xff1a;python2.7和python3.6之前已经…

计算机网络 第五章传输层

文章目录 1 传输层的功能2 传输层两种协议&#xff1a;UDP和TCP3 端口和端口号4 UDP数据报特点和首部格式5 UDP校验6 TCP协议的特点7 TCP报文段首部格式8 TCP连接&#xff1a;三次握手建立连接9 TCP连接&#xff1a;四次挥手释放连接10 TCP可靠传输11 TCP流量控制12 TCP拥塞控制…

快速入手maven

文章目录 Maven介绍Maven安装和配置基于IDEA的Maven工程创建梳理Maven工程GAVP属性Idea构建Maven JavaSE工程Idea构建Maven JavaEE工程1. 手动创建2. 插件方式创建 Maven工程项目结构说明Maven核心功能依赖和构建管理依赖传递和冲突依赖导入失败场景和解决方案扩展构建管理和插…

时间复杂度的计算技巧-算法模型中的时间复杂度如何计算,有哪些技巧呢

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下时间复杂度的计算技巧-算法模型中的时间复杂度如何计算&#xff0c;有哪些技巧呢&#xff0c;算法的时间复杂度是评估算法性能和效率的一种方式&#xff0c;它表示算法需要执行多少次基本操作才能完成其任务&#x…

k8s-服务网格实战-入门Istio

istio-01.png 背景 终于进入大家都比较感兴趣的服务网格系列了&#xff0c;在前面已经讲解了&#xff1a; 如何部署应用到 kubernetes服务之间如何调用如何通过域名访问我们的服务如何使用 kubernetes 自带的配置 ConfigMap 基本上已经够我们开发一般规模的 web 应用了&#xf…

app逆向入门之车智赢

声明&#xff1a;本文仅限学习交流使用&#xff0c;禁止用于非法用途、商业活动等。否则后果自负。如有侵权&#xff0c;请告知删除&#xff0c;谢谢&#xff01;本教程也没有专门针对某个网站而编写&#xff0c;单纯的技术研究 目录 案例分析技术依赖参数分析效果展示代码分享…

电压放大器可用于什么场合

电压放大器是电子器件中常见的一种放大器类型&#xff0c;它可以将输入信号的电压放大到更大的幅度&#xff0c;以满足特定应用的需求。电压放大器广泛应用于多个领域和场合&#xff0c;下面将详细介绍一些使用电压放大器的场景。 音频放大器&#xff1a;音频放大器是电压放大器…