【数集项目之 MCDF】(一) 控制寄存器 control_register

news2024/11/15 15:40:52

写在前面

  本项目为MCDF数据整形器设计,所有的参考代码见我的github

https://github.com/SuperiorLQF/verilog_ALL/tree/master/MCDF

  其中设计的参考文档见github文件中的MCDF修订版.docx文件。选择的工具链是Vscode & iverilog & gtkwave,相关工具的安装与环境配置就不介绍了,可以参考其他文章。

注意:不同的工具链代码可能有区别,例如一些集成开发环境不需要书写`include,而是直接将代码加入工程作为替代

  MCDF模块按照子模块划分,总共分为了control_registerslvae_FIFOarbiterformatter这几个子模块和MCDF这个顶层模块。本章首先从控制寄存器control_register开始介绍,这样的安排顺序更容易对于模块整体有系统性的理解。
  下面我们正式开始介绍。


第一节 control_register文档理解

  将设计文档中控制寄存器control_register的设计文档相关内容引用如下

1.接口描述及其时序
  控制寄存器接口时序如图所示。在每个时钟周期根据cmd命令完成指定操作。当cmd为写指令时,将数据cmd_data_i写入cmd_addr指定的寄存器中。当cmd为读指令时,从cmd_addr指定的寄存器中的数据读出,并在下一个时钟周期送到cmd_data_o端口。当cmd为其它指令时不进行任何操作。
在这里插入图片描述
2.接口信号
  见设计文档,这里不在赘述。

  首先我们看到,cmd_i[1:0]是一个2位的命令输入,但是设计里没有规定WRRDidle各自的对应二进制码,因此这里进行自己定义:选择按照one-hotRDWR进行编码

cmd_i[1:0]对应命令
01RD
10WR
00/11idle

  接着,我们观察时序发现,一次只能执行一种指令,因此不同于同时读写的存储器写法,只需要简单的 always-case 语句就可以实现,这里需要注意。
  此外,需要关注电路的同步性,电路的特性类似于D触发器。cmd_addrcmd在一个时钟周期内是对应的,即在时钟上升沿到来之前(本时钟周期)给定,在始终上升沿触发时(下一时钟周期)完成对应的操作。因此,在图中cmd_addr=0x04,cmd=RD时,在下一时钟周期才会读出数据D2
  弄清了基本时序之后,下面来观察控制寄存器内部的具体存储结构。文档中给出说明,三个通道每个通道都对应2个寄存器单元**:控制寄存器单元状态寄存器单元**。每个单元都是标准的32位寄存器。
  control_register中的寄存器安排如下(这里相比于设计文档有小的调整)

地址寄存器单元描述
0x00slave0的控制寄存器
0x04slave1的控制寄存器
0x08slave2的控制寄存器
0x0Cslave0的状态寄存器
0x10slave1的状态寄存器
0x14slave2的状态寄存器

  对于控制寄存器和状态寄存器有如下规定:

控制寄存器,32bit,可读写,位定义为:

  • bit[0] :通道使能信号。1为打开,0为关闭。复位值为1
  • bit[2:1] :优先级。0为最高,3为最低。复位值为3
  • bit[5:3] :数据包长度。0对应长度4,1对应8,2对应16,3对应32。其它数值均暂时对应32。复位值为0
  • bit[31:6] :保留位,不能写入。复位值为0。


状态寄存器,32bit,只读,位定义为:

  • bit[ 7: 0] :从端FIFO0的可写余量,实时同步FIFO0的余量,复位值为FIFO深度值
  • bit[31:8] :保留位,复位值为0。

  重点关注其复位值,因为需要在always-reset中进行描述.
  由于3个控制寄存器的复位值是一样的,3个状态寄存器亦如此,因此可以在模块中设置参数parameter来进行赋值复位,以增强代码可读性和可维护性。

parameter   CTRL_REG_DEFAULT='b111,
           	STATE_REG_DEFAULT=32'd63//FIFO深度63

  这里FIFO深度规定为63而不是64是因为:64=26,表示0-64需要[6:0]共7位二进制数,而文档中虽然在状态寄存器这里给了8位存储空间,但是在margin这里只给了[5:0]共6位位宽,因此这里将深度改为63,就可以在6位位宽的margin中进行传输。
  输出对应:前面已经说了数据、地址、指令这些输入输出,但我们发现,control_register中还有一些IO,例如slvx_margin_i[5:0]slvx_en_oslvx_pkglen_o[2:0],slvx_prio_o[1:0] ,
  这些都是什么含义?观察文档中这些IO信号的注释,我们发现,它们就是控制寄存器和状态寄存器对应位的描述。
  举例而言,控制寄存器bit[2:1]描述是该通道的优先级,因此slvx_prio_o[2:1]应当就是该寄存器对应位的值。那么实际上这些信号就是寄存器对应位的信号通过wire直接引出来罢了。
  综合以上,我们对control_register设计有了具体把握,下面就进行verilog设计代码编写。


第二节 control_register代码实现

模块文件名:control_register.v
注释见代码内

/*************************<MCDF控制寄存器>*********************/
//存储器仅在时钟周期完成读或写,并不完成同时读写
`timescale 1ns/100ps
/*************************<端口声明>*********************/
module control_register
#(
    parameter   CTRL_REG_DEFAULT='b111,
                STATE_REG_DEFAULT=32'd63//FIFO深度63
              
)
(
    input                   clk_i,
                            rstn_i,
    input   wire    [1:0]   cmd_i ,
    input   wire    [5:0]   cmd_addr_i,
    input   wire    [31:0]  cmd_data_i,    
    input   wire    [5:0]   slv0_margin_i,
                            slv1_margin_i,
                            slv2_margin_i,


    output                  slv0_en_o,
                            slv1_en_o,
                            slv2_en_o,    
    output  reg     [31:0]  cmd_data_o,
    output  wire    [1:0]   slv0_prio_o,
                            slv1_prio_o,
                            slv2_prio_o,
    output  wire    [2:0]   slv0_pkglen_o,
                            slv1_pkglen_o,
                            slv2_pkglen_o
);
/*************************<中间信号>*********************/
reg     [31:0]   Register    [5:0];//6个寄存器构成的存储单元
integer i;
/*************************<时序电路>*********************/
always @(posedge clk_i or negedge rstn_i) begin
    if(!rstn_i)begin					//给寄存器赋复位值
        for(i=0;i<3;i=i+1)begin
            Register[i]<=CTRL_REG_DEFAULT;
        end
        for(i=3;i<6;i=i+1)begin
            Register[i]<=STATE_REG_DEFAULT;
        end
        cmd_data_o<='d0;				//!!!不加这句不给综合
    end
    else begin
        case (cmd_i)
        //!!!这里没有加入状态寄存器不能写的约束,所有寄存器均可读写,并且读取的通道余量是延迟一个时钟的
            2'b01:cmd_data_o<=Register[cmd_addr_i>>2];//RD
            2'b10:Register[cmd_addr_i>>2]<=cmd_data_i;//WR
            default: //IDLE
                ;						//不做任何操作但是要加上,防止综合出锁存器
        endcase
        								//!!!锁存更新通道余量,不是实时的,会延迟一个时钟
        Register[3][5:0]<=slv0_margin_i;
        Register[4][5:0]<=slv1_margin_i;
        Register[5][5:0]<=slv2_margin_i;        
    end
end
/*************************<组合逻辑电路>*********************/
//通道使能信号
assign slv0_en_o=Register[0][0];
assign slv1_en_o=Register[1][0];
assign slv2_en_o=Register[2][0];
//通道优先级
assign slv0_prio_o=Register[0][2:1];
assign slv1_prio_o=Register[1][2:1];
assign slv2_prio_o=Register[2][2:1];
//数据包长度
assign slv0_pkglen_o=Register[0][5:3];
assign slv1_pkglen_o=Register[1][5:3];
assign slv2_pkglen_o=Register[2][5:3];
endmodule

  对其进行编译,通过,下面进行testbench编写


第三节 control_register testbench代码实现

这里根据参考波形给出相应的激励,需要注意的主要有2点

  • tb中的输入reg信号都要用非阻塞赋值<=
  • 与时钟沿同步的激励信号必须用@(posedge/negedge clk_i),否则仿真时会出现时序错误
    tb文件名:control_register_tb.v
    注释见代码内
`timescale 1ns/100ps
`include "control_register.v"
/*************************<端口声明>*********************/
module control_register_tb;
reg             clk_i,
                rstn_i;
reg     [1:0]   cmd_i;
reg     [5:0]   cmd_addr_i;
reg     [31:0]  cmd_data_i;    
reg     [5:0]   slv0_margin_i,
                slv1_margin_i,
                slv2_margin_i;


wire            slv0_en_o,
                slv1_en_o,
                slv2_en_o;    
wire    [31:0]  cmd_data_o;
wire    [1:0]   slv0_prio_o,
                slv1_prio_o,
                slv2_prio_o;
wire    [2:0]   slv0_pkglen_o,
                slv1_pkglen_o,
                slv2_pkglen_o;
/*************************<原件例化>*********************/
control_register cr1(
                clk_i,
                rstn_i,
                cmd_i,
                cmd_addr_i,
                cmd_data_i,   
                slv0_margin_i,
                slv1_margin_i,
                slv2_margin_i,
                
                slv0_en_o,
                slv1_en_o,
                slv2_en_o,
                cmd_data_o,
                slv0_prio_o,
                slv1_prio_o,
                slv2_prio_o,
                slv0_pkglen_o,
                slv1_pkglen_o,
                slv2_pkglen_o
);
/*************************<激励信号>*********************/
initial begin
    clk_i=0;
    rstn_i=0;
    cmd_i='b00;
    cmd_addr_i='b00;
    cmd_data_i='h00;  
    slv0_margin_i='d21;
    slv1_margin_i='d33;
    slv2_margin_i='d45;    
    $dumpfile("control_register.vcd");
    $dumpvars;
    #25 rstn_i=1;
    @(posedge clk_i)begin
        cmd_i<='b10;
        cmd_addr_i<='d00;//特别注意要非阻塞赋值
        cmd_data_i<='hD1;     
    end
    @(posedge clk_i)begin
        cmd_i<='b10;
        cmd_addr_i<='d04;
        cmd_data_i<='hD2;     
    end
    @(posedge clk_i)begin
        cmd_i<='b10;
        cmd_addr_i<='d08;
        cmd_data_i<='hD3;     
    end
    @(posedge clk_i)begin
        cmd_i<='b00;
        cmd_addr_i<='d08;
        cmd_data_i<='hD3;     
    end
    @(posedge clk_i)begin
        cmd_i<='b10;
        cmd_addr_i<='d00;
        cmd_data_i<='hD4;     
    end
    @(posedge clk_i)begin
        cmd_i<='b01;
        cmd_addr_i<='d04;
        cmd_data_i<='hD4;     
    end
    @(posedge clk_i)begin
        cmd_i<='b01;
        cmd_addr_i<='d00;
        cmd_data_i<='hD4;     
    end
    #500 $finish;
end
always #10
    clk_i<=~clk_i;

endmodule

  成功编译之后,生成vcd波形文件,下面使用gtkwave观察波形


第四节 control_registervcd波形观察

  在terminal中cd到当前文件夹下,输入

gtkwave control_register.vcd

  然后手动查看需要看的信号,如下图所示
请添加图片描述  与参考波形相同,简单验证完成。


补充

  波形保存:当我们需要保存波形时,点击Write Save File就可以保存波形文件,格式为.gtkw,当下次需要查看时,就可以直接导入gtkw文件,而直接导入vcd文件就不会看到之前已经拉出的波形。

在这里插入图片描述  至此,control_register设计及检查完毕,下一章将从slave_FIFO开始详述设计过程。


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

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

相关文章

前端框架 Nuxt3 Vue3 SSR 总结

目录 一、Nuxt3安装 二、路由 1、普通路由 2、动态路由 3、获取路由参数 4、路由跳转标签 5、路由跳转api 三、静态资源 四、常用标签 1、title标签、useHead的API 五、公共模板布局 1、默认布局 2、自定义公共模板 3、动态自定义布局 六、插件 七、中间件 …

【QString 函数学习篇】

【QString 函数学习篇】【1】UI设计布局【2】QChar | setAlignment |【3】sprintf | asprintf | setNum | number |【4】toInt | toUpper [十进制->十六进制 | 十进制->二进制]【5】clear | append【6】二进制->十六进制 | 二进制->十进制【7】prepend【8】strimme…

[附源码]Python计算机毕业设计SSM基于的餐厅管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

(十二)Vue之列表渲染

文章目录基本列表遍历数组遍历对象遍历字符串遍历指定次数key的原理虚拟DOM中key的作用用index作为key可能会引发的问题如何选择keyVue学习目录 上一篇&#xff1a;&#xff08;十一&#xff09;Vue之条件渲染 基本列表 在vue里基本的列表渲染可以使用v-for指令 v-for指令: …

Reactor手册

Flux Flux 是一个发出0-N个元素组成的异步序列的Publisher,可以被onComplete信号或者onError信号所终止。 Flux.just("Hello", "World").subscribe(System.out::println);// fromArray()&#xff0c;fromIterable()&#xff0c;fromStream()Flux.fromArra…

K8s 核心组件介绍

目录前言一、控制平面组件1.1 kube-apiserver1.2 etcd1.3 kube-scheduler1.4 kube-controller-manager1.5 cloud-controller-manager二、Node 组件2.1 kubelet2.2 kube-proxy2.3 Container Runtime前言 一个完整的 K8s 集群由一组节点&#xff08;node&#xff09;服务器组成&…

组队-蓝桥杯

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 作为篮球队教练&#xff0c;你需要从以下名单中选出 11 号位至 55 号位各一名球员&#xff0c;组成球队的首发阵容。 每位球员担任 11 号位至 55 号位时的评分如下…

关于人脸检测和人脸关键点检测的详解(涉及Opencv 和Dlibd)

关于人脸识别&#xff0c;大家入门opencv&#xff0c;最常见的是用opencv级联分类器器里面的函数进行人脸的识别&#xff08;当然里面包含很多各种物体的分类器&#xff0c;大家可以一一测试&#xff09;&#xff0c;今天我们来练一下关于人脸识别的级联器。 1&#xff0c;ope…

数据仓库(DW)、数据湖、数据中台的关系

一句话说明&#xff1a;数据中台是一套体系&#xff0c;既不是工具又不是存储&#xff0c;它可以包含数据湖和数据仓库。 数据仓库 数据仓库是一个面向主题的、集成的、随时间变化但信息本身相对稳定的数据集合&#xff0c;用于支持管理决策过程。其本质就是完成从面向业务过程…

[附源码]Python计算机毕业设计Django-菜篮子系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

一文学会jenkins pipline自动化构建

01 Pipeline流水线基本语法 首先创建 在jenkins上创建一个pipeline的流水线任务 新建ITEM–>选择流水线 基本pipeline脚本结构 pipeline {//agent 表示要执行的节点&#xff0c;any表示任意节点 agent any //stages表示任务执行时的所有步骤集合 stages { /…

企业销售CRM的主要优势是什么?

民营企业商品销售CRM的主要就竞争优势是什么? 新一代研究说明&#xff0c;由于差劲的顾客新体验&#xff0c;或内公司每月经济损失750亿元。为了更快地介绍您的顾客&#xff0c;您须要两个智能化的顾客管理工作系统。因而&#xff0c;您能提供更多直接影响您的商品销售的高质…

Python调用C++

1 背景 python被称为胶水语言&#xff0c;其优势是能够粘结各种不同的语言。同时&#xff0c;python有着更大的“亲民性”&#xff0c;很容易进行开发。但是&#xff0c;python最大的问题就是计算速度不够。通常可以用CUDA或者C对一个python程序进行加速&#xff0c;加速策略如…

【LeetCode】单词搜索 II [H](前缀树)

212. 单词搜索 II - 力扣&#xff08;LeetCode&#xff09; 一、题目 给定一个 m x n 二维字符网格 board 和一个单词&#xff08;字符串&#xff09;列表 words&#xff0c; 返回所有二维网格上的单词 。 单词必须按照字母顺序&#xff0c;通过 相邻的单元格 内的字母构成&am…

QT系列第2节 QT中元对象系统

QT是在标准C上进行了扩展&#xff0c;所以就有自己的特性&#xff0c;其中元对象系统就是其一。元对象系统有点类似于java和go语言中的反射&#xff0c;让我们在编程时解决问题多了些方法和思路&#xff0c;关于元对象可以简单总结出以下内容项。 目录 一.元对象要点总结 二…

Linux转发性能评估与优化之——转发瓶颈分析与解决方案

线速问题 很多人对这个线速概念存在误解。认为所谓线速能力就是路由器/交换机就像一根网线一样。而这&#xff0c;是不可能的。应该考虑到的一个概念就是延迟。数据包进入路由器或者交换机&#xff0c;存在一个核心延迟操作&#xff0c;这就是选路&#xff0c;对于路由器而言&…

软件工程复习简略

软件工程复习简略1.什么是软件生存周期&#xff1f;通常可划分为哪些阶段&#xff1f;2.简述需求分析要经过哪些步骤&#xff0c;每个步骤的作用。3.详细设计有哪些常用工具&#xff1f;&#xff08;注意Pad图的画法&#xff09;4.软件测试的目的和原则是什么&#xff1f;5.测试…

pythonselenium自动化测试实战项目(完整、全面)

前言 之前的文章说过&#xff0c; 要写一篇自动化实战的文章&#xff0c; 这段时间比较忙再加回家过11一直没有更新博客&#xff0c;今天整理一下实战项目的代码共大家学习。&#xff08;注:项目是针对我们公司内部系统的测试&#xff0c;只能内部网络访问&#xff0c;外部网络…

【SpringCloud负载均衡】【源码+图解】【三】LoadBalancer的工作原理

【SpringCloud负载均衡】【源码图解】【二】LoadBalancer配置 目录3. LoadBalancer的工作原理3.1 创建LoadBalancerRequest3.2 创建上下文3.2.1 properties3.2.2 configurations3.2.3 contexts3.3 获取ReactiveLoadBalancer3.4 获取ServiceInstance3.5 向serviceInstance请求结…

Java要学到什么程度才可以找工作?

Java为不同的集合提供了一个集合框架。集合基于数据结构&#xff0c;比如常见的&#xff1a;列表、数组、集合、哈希图等等。因此&#xff0c;在研究集合时&#xff0c;最好了解一点数据结构的相关知识。 主要副题&#xff1a; List Set Map ArrayList LinkedList Queue…