11.7加减计数器,可置位~,数字钟分秒,串转并,串累加转并,24位串并128,流水乘法器,一些乘法器

news2024/12/23 22:12:06

 信号发生器

方波,就是一段时间内都输出相同的信号

 

锯齿波就是递增

三角波就是先增后减

加减计数器

当mode为1则加,Mode为0则减;只要为0就输出zero 

这样会出问题,因为要求是十进制,但是这里并没有考虑到9之后怎么办,所以就会使number输出超过9,应该额外要添加十进制的边缘判断,即mode为1,要加的时候也要判断一下是不是要继续加,而不是直接加

简易秒表

输出端口second为1~60,到60时,minute+1,分到60时,停止计数

秒的确定

分的确定

可置位计数器

就是有置位信号时,把当前数字置为要置的数字

然后要确定是十六进制

额外逻辑

串转并

输入端输入单位信号,累积到6个后,输出一个六位的信号

reg [5:0]       data_reg;

reg [2:0]       data_cnt;


always @(posedge clk or negedge rst_n ) begin

       if(!rst_n)

              ready_a <= 'd0;

       else

              ready_a <= 1'd1;

end

always @(posedge clk or negedge rst_n ) begin

       if(!rst_n)

              data_cnt <= 'd0;

       else if(valid_a && ready_a)

              data_cnt <= (data_cnt == 3'd5) ? 'd0 : (data_cnt + 1'd1);

end

always @(posedge clk or negedge rst_n ) begin

       if(!rst_n)

              data_reg <= 'd0;

       else if(valid_a && ready_a)

              data_reg <= {data_a, data_reg[5:1]};

end


always @(posedge clk or negedge rst_n ) begin

       if(!rst_n)begin

              valid_b <= 'd0;

              data_b <= 'd0;

       end

       else if(data_cnt == 3'd5)begin

              valid_b <= 1'd1;

              data_b <= {data_a, data_reg[5:1]};

       end

       else

              valid_b <= 'd0;

end

数据累加输出

当接受到4个输入数据后,输出一个这四个数据的累加结果

`timescale 1ns/1ns

module valid_ready(
	input 				clk 		,   
	input 				rst_n		,
	input		[7:0]	data_in		,
	input				valid_a		,
	input	 			ready_b		,
 
 	output		 		ready_a		,
 	output	reg			valid_b		,
	output  reg [9:0] 	data_out
);
reg 	[1:0]		data_cnt;

assign ready_a = !valid_b | ready_b;

always @(posedge clk or negedge rst_n ) begin
	if(!rst_n) 
		data_cnt <= 'd0;
	else if(valid_a && ready_a)
		data_cnt <= (data_cnt == 2'd3) ? 'd0 : (data_cnt + 1'd1);
end
always @(posedge clk or negedge rst_n ) begin
	if(!rst_n) 
		valid_b <= 'd0;
	else if(data_cnt == 2'd3 && valid_a && ready_a)
		valid_b <= 1'd1;
	else if(valid_b && ready_b)
		valid_b <= 1'd0;
end

always @(posedge clk or negedge rst_n ) begin
	if(!rst_n) 
		data_out <= 'd0;
	else if(ready_b && valid_a && ready_a && (data_cnt == 2'd0))
		data_out <= data_in;
	else if(valid_a && ready_a)
		data_out <= data_out + data_in;
	
end


endmodule

非阻塞赋值,就是把次态给现态,就是说右侧的是次态,但是现在还不用,是下个状态的情况,那么条件判断里就是导致其进入下个状态的条件

非整数倍数据位宽转换24to128

数据位宽转换,24位转128位,先到的数据为高位

也是串转并的一种,只不过最后的时候是只要一部分

思路都是,先判断输入的有效性,有效时,就对数据暂存器做出改变;对于输出时,如果可以输出了,即让输出,就输出,没有使能,就不输出,依然暂存。

24和128的最小公倍数为384,所以每到384的时候,就是对齐了一次,即完成一次周期

所以每当cnt到5,10,15时,就需要输出一次,并拉高valid_out一个周期

简单的输入信号计数器,表示已经输入了几个24位的信号

数据暂存器,每当输入有效时,将数据从低位移入,注意是低位,而且是要在输入有效时操作

输出使能

需要注意的是,非阻塞是使的关系,即这个clk里收到了信号,但是并不在这个周期里即时发生改变,而是在下个clk里再发生改变,也就使得逻辑上同步的输入输出,不是在同一个周期上发生,而是先有输入,才有下个周期对应的输出,每个周期输出的都是上个周期的结果。当下输入的数据,在下个周期出结果

但在赋值时,由于是非阻塞,所以也是在给次态赋值,所以这个周期里干的事,都不是这个周期里的,而是去确定下个周期的,这个周期里的事都在上个周期里确定了;也就是说此时的条件都是下个周期的,而不是当下的。

所以写的时候,就不要想的是串行。而是想写的是一个一个模块,根据不同的输入给出不同的输出

就是注意

 先到的数据在高位,满的时候,先从高位出去,即FIFO。只是截取高位的时候,是从暂存器的低位开始截取的,也就是说,还是先进的最高位先出去;然后输出的时候,是先尝试输出再寄存,因为寄存的时候不管截不截取,它就是全部存进去。但是输出的时候,要判断并截取一部分新的

valid_in是判断当前的输出是不是有效,如果无效,即使输入了,要发生一些改变时,也不会

 

之前担心的是,如果能输出的时候,先在暂存器里输入了一遍,结果又在输入里输入了一遍

但实际上,这就是为什么要用非阻塞而不是阻塞。即各个模块都是并行的,都是并行的,即在这个时钟刻里,用的都是上个时间里的数值,而且不会发生改变。用非阻塞可以不用考虑这样的先后问题,如果是阻塞,就必须先尝试输出,才能暂存

用阻塞也会出问题,出时序问题,马丹

`timescale 1ns/1ns

module width_24to128(
	input 				clk 		,   
	input 				rst_n		,
	input				valid_in	,
	input	[23:0]		data_in		,
 
 	output	reg			valid_out	,
	output  reg [127:0]	data_out
);
    reg [3:0]   cnt;
    reg [127:0] data_lock;
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            cnt <= 0;
        else
            cnt <= ~valid_in? cnt:cnt+1;
    end
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            valid_out <= 0;
        else
            valid_out <= (cnt==5 || cnt==10 || cnt==15)&&valid_in;
    end
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            data_lock <= 0;
        else
            data_lock <= valid_in? {data_lock[103:0], data_in}: data_lock;
    end
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n)
            data_out <= 0;
        else if(cnt==5)
            data_out <= valid_in? {data_lock[119:0], data_in[23:16]}: data_out;
        else if(cnt==10)
            data_out <= valid_in? {data_lock[111:0], data_in[23: 8]}: data_out;
        else if(cnt==15)
            data_out <= valid_in? {data_lock[103:0], data_in[23: 0]}: data_out;
        else
            data_out <= data_out;
    end
endmodule

流水线乘法器 

流水线

就是采用乘法竖式的思想,将乘法转化加法,最高位为n,则就有n个加法数

用循环简化代码

`timescale 1ns/1ns

module multi_pipe#(
	parameter size = 4
)(
	input 						clk 		,   
	input 						rst_n		,
	input	[size-1:0]			mul_a		,
	input	[size-1:0]			mul_b		,
 
 	output	reg	[size*2-1:0]	mul_out		
);
wire [2*size-1 : 0] a,b;
reg  [2*size-1 : 0]temp0,temp1,temp2,temp3;
assign a=mul_a;
assign b=mul_b;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
temp0<=0;
temp1<=0;
temp2<=0;
temp3<=0;
end
else
begin
temp0 <= b[0] ? a : 0;
temp1<=  b[1] ? a<<1 : 0; 
temp2<=  b[2] ? a<<2 : 0; 
temp3<=  b[3] ? a<<3 : 0; 
end
end
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
mul_out=0;
end
else
begin
mul_out=temp0+temp1+temp2+temp3;
end

end
endmodule

 

`timescale 1ns/1ns

module multi_pipe#(
	parameter size = 4
)(
	input 						clk 		,   
	input 						rst_n		,
	input	[size-1:0]			mul_a		,
	input	[size-1:0]			mul_b		,
 
 	output	reg	[size*2-1:0]	mul_out		
);
    //parameter 
    parameter N = size * 2;
    //defination
    wire [N - 1 : 0] temp [0 : 3];
    
    reg [N - 1 : 0] adder_0;
    reg [N - 1 : 0] adder_1;
    
    //output 
    genvar i;
    generate
        for(i = 0; i < 4; i = i + 1)begin : loop
            assign temp[i] = mul_b[i] ? mul_a << i : 'd0;
        end
    endgenerate
    
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) adder_0 <= 'd0;
        else adder_0 <= temp[0] + temp[1];
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) adder_1 <= 'd0;
        else adder_1 <= temp[2] + temp[3];
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) mul_out <= 'd0;
        else mul_out <= adder_0 + adder_1;
    end
endmodule

 

就是说,一个数位数是否为1,决定另一个数是否为拓位后的数还是0

状态图实现任意位乘法

2个32位整数相乘,实际上是进行了32次加法操作

流程图中,x因为需要左移,所以32位长度的x应该用一个64位寄存器来存储,这样才能保证x左移后不会发生高位丧失。

取绝对值操作

首先是获取符号位,然后根据符号位去决定对应的操作

如果是正数,就直接赋值;不然,就先取反再+1

输入为mult_begin,拉高后乘法再开始,直到运算结束,或者人为拉低

需要注意的是,右移y,那么每次都是去掉y的最低位,然后需要在最高位补0,即整体往右移动一位;这个块就是实现每次都右移一位y

这个是左移x,不会丢位,因为最多移32次,最多就是到最高位

然后这个是判断加数,如果此时y的最低位是1,那么就加;不然,就不加为0;

符号位确定

循环实现

相同的思路,第二种就是用for循环简化了代码

采用移位寄存器同样可以实现,上面那个是每次都计算,都是从头开始移位i次,采用移位寄存器后就是不断复用上一次的结果,只移位一次就可以,而不是每次都移位i次

用i,i就代表移位的次数,可以简便的读取到第i位,以及左移i位的结果

流水线是每次都加两个新的,

仿真文件

`timescale 1ns / 1ps
 
module tb;
 
    // Inputs
    reg clk;
    reg mult_begin;
    reg [31:0] mult_op1;
    reg [31:0] mult_op2;
 
    // Outputs
    wire [63:0] product;
    wire mult_end;
 
    // Instantiate the Unit Under Test (UUT)
    multiply uut (
        .clk(clk), 
        .mult_begin(mult_begin), 
        .mult_op1(mult_op1), 
        .mult_op2(mult_op2), 
        .product(product), 
        .mult_end(mult_end)
    );
 
    initial begin
        // Initialize Inputs
        clk = 0;
        mult_begin = 0;
        mult_op1 = 0;
        mult_op2 = 0;
 
        // Wait 100 ns for global reset to finish
        #100;
        mult_begin = 1;
        mult_op1 = 32'H00001111;
        mult_op2 = 32'H00001111;
        #400;
        mult_begin = 0;
        #500;
        mult_begin = 1;
        mult_op1 = 32'H00001111;
        mult_op2 = 32'H00002222;
        #400;
        mult_begin = 0;
        #500;
        mult_begin = 1;
        mult_op1 = 32'H00000002;
        mult_op2 = 32'HFFFFFFFF;
        #400;
        mult_begin = 0;
        #500;
        mult_begin = 1;
        mult_op1 = 32'H00000002;
        mult_op2 = 32'H80000000;
        #400;
        mult_begin = 0;
        // Add stimulus here
    end
   always #5 clk = ~clk;
endmodule
 

一些细节 

这是两者的位数关系

非流水线设计就是每次乘法运算只输出一个结果

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

openvino学习(一)ubuntu20.04安装openvino2022

安装openvino2022要求 操作系统 Ubuntu 18.04 长期支持 (LTS)&#xff0c;64 位 Ubuntu 20.04 长期支持 (LTS)&#xff0c;64 位 软件 CMake 3.13 或更高版本&#xff0c;64 位 GCC 7.5.0&#xff08;适用于 Ubuntu 18.04&#xff09;或 GCC 9.3.0&#xff08;适用于 Ubunt…

工具介绍——第三方软件远程连接(工具:Rustdesk)

文章目录 前言一、使用工具二、开始演示1、拿下目标主机权限后上传文件2、运行目标主机上的rustdesk-1.1.9.exe文件3、目标主机上whoami查看现在的用户4、查找目标主机上连接的文件&#xff0c;并添加连接密码5、目标主机重启rustdesk的应用程序6、本地连接主机 前言 这里主要…

“第六十三天”

这两天怎么做的这么别扭&#xff0c;为什么我的vs 的strlen函数包括终止字符了&#xff1b; 哦哦&#xff0c;明白了&#xff0c;fgets函数读取在未达到指定字长&#xff0c;或者遇见空白符之前&#xff0c;会读取前面的所有字符&#xff0c;所以会读取换行符&#xff0c;而get…

康耐视深度学习ViDi-View菜单介绍

Accept View承认当前图片标注的有效性 Clear Marking 清除当前图片的标注特征 Clear Marking & Labels清除当前图片的标注特征和标签 Process处理当前图片 Edit ROI编辑检测的区域 Edit Regions编辑(标注)特征区域 Edit Mask 编辑遮挡(屏蔽)区域 Apply Mask To Tool将遮挡(…

杨辉三角(Java实现)

public class Demo09 {public static void main(String[] args) {//第一位和最后一位都为1//除了每行的第一列之外,其余的数为a[i][j]aa[i-1][j]a[i-1][j-1];int[][] arrays new int[10][10];for(int i 0;i<10;i){if(i0){ //第一行直接赋值为0arrays[i][0]1;continue;//重…

深入理解强化学习——多臂赌博机:基于置信度上界的动作选择

分类目录&#xff1a;《深入理解强化学习》总目录 因为对动作—价值的估计总会存在不确定性&#xff0c;所以试探是必须的。贪心动作虽然在当前时刻看起来最好&#xff0c;但实际上其他一些动作可能从长远看更好。 ϵ − \epsilon- ϵ−贪心算法会尝试选择非贪心的动作&#xf…

ZipInputStream解压报错java.lang.IllegalArgumentException: MALFORMED

背景 使用jdk自带的zip工具ZipInputStream&#xff0c;去读取使用winrar在中文windows制作出来的zip文件报错。 Exception in thread "main" java.lang.IllegalArgumentException: MALFORMEDat java.util.zip.ZipCoder.toString(ZipCoder.java:58)at java.util.zip…

Qwt QwtWheel绘制滚动轮

1.简介 QwtWheel 是一个用于实现滚动轮控件的类库。它基于 Qt 框架&#xff0c;并提供了一些方便的功能来处理滚动轮的事件和绘图。 QwtWheel 类继承自 QWidget类&#xff0c;用于定义滚动轮控件的通用行为。QwtWheel 添加了特定于滚动轮的功能。 QwtWheel 可以用于创建具有滚…

Spring Cloud之多级缓存

目录 传统缓存 多级缓存 JVM进程缓存 Caffeine 缓存驱逐策略 实现进程缓存 常用Lua语法 数据类型 变量声明 循环使用 定义函数 条件控制 安装OpenResty 实现Nginx业务逻辑编写 请求参数解析 实现lua访问tomcat JSON的序列化和反序列化 Tomcat的集群负载均衡 …

云表平台突破传统,企业级低代码让软件开发速度提升

随着数字化进程的加速推进&#xff0c;软件开发效率和成本的要求也在日益提高。在这个背景下&#xff0c;低代码技术的出现为企业软件开发提供了新的解决方案。低代码开发平台以其简单易用、高效灵活的特点&#xff0c;已经成为各行各业企业进行应用开发的首选工具。 企业中低代…

生成无损压缩png和有损压缩png的做法

作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> png是一种常用的图像格式。png一般为无损压缩,但是可以是有损压缩的。 下图都是100x100的png图像,一个是无损压缩,一个是有损压缩。 看着效果基本一样,但是它们的大小相差很大,无损…

个体诊所管理系统电子处方软件,个体诊所人员服务软件,佳易王电子处方开单系统

个体诊所管理系统电子处方软件&#xff0c;个体诊所人员服务软件&#xff0c;佳易王电子处方开单系统 软件功能&#xff1a; 1、常用配方模板&#xff1a;可以自由添加配方分类&#xff0c;预先设置药品配方。 2、正常开药&#xff1a;可以灵活选择药品&#xff0c;用法用量&…

Qt 4.8.6 的下载与安装

Qt 4.8.6 的下载与安装 Qt 4.8.6 的下载与安装下载并解压 MinGW 4.8.2Qt4.8.6 库的安装Qt Creator 3.3.0 的安装配置 Qt Creator测试 官方博客&#xff1a;https://www.yafeilinux.com/ Qt开源社区&#xff1a;https://www.qter.org/ Qt 4.8.6 的下载与安装 学习《Qt Creato…

链表题(1)

链表题 今天给大家带来道链表题的练习 链表的中间节点 先给大家奉上链接&#xff1a; https://leetcode.cn/problems/middle-of-the-linked-list/description/ 题目描述; 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0…

day4作业

设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数、拷贝赋值函数。 #include <iostream>using name…

一句话说明:企业架构框架鼻祖Zachman

问&#xff1a;禁止废话&#xff0c;一句话表达&#xff0c;Zachman是什么&#xff1f;包含哪些内容&#xff1f; 韩老师正经回答&#xff1a;Zachman是企业架构框架鼻祖&#xff0c;包含6行6列的矩阵式架构内容。6列是5W1H&#xff08;What、How、Where、Who、When、Why&…

技术分享 | app自动化测试(Android)--App 控件定位

客户端的页面通过 XML 来实现 UI 的布局&#xff0c;页面的 UI 布局作为一个树形结构&#xff0c;而树叶被定义为节点。这里的节点也就对应了要定位的元素&#xff0c;节点的上级节点&#xff0c;定义了元素的布局结构。在 XML 布局中可以使用 XPath 进行节点的定位。 App的布…

物联网AI MicroPython学习之语法 uhashlib哈希算法

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; uhashlib 介绍 实现二进制数据散列算法&#xff0c;支持sha256&#xff0c;sha1&#xff0c;MD5。 接口介绍 sha256 - 创建一个SHA256哈希对象 参数原型&#xff1a;hash_obj uhashlib.sha256([bytes]) …

CMD命令行中如何切换路径。

问题描述&#xff1a; windows命令行中我记得切换命令是cd E:命令就行了呀。但是现在好像不行了。 问题解决&#xff1a;现在windows命令行中切换命令需要在cd E:之间增加一个/D。注意是/D&#xff0c;不是\D。 具体命令如下&#xff1a;CD /D E: 结果如下如所示&#xff1a…

企业级低代码平台需具备的关键能力解析

低代码是数字化转型浪潮下的产物&#xff0c;国内外已经生产出了很多成熟的产品。目的是让企业以更低的成本、更快的周期、更易操作的方式完成企业数字化布局&#xff0c;以实现内部的高效工作。 一、什么是“企业级”低代码&#xff1f; 首先&#xff0c;我们先回答什么是“…