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

2023-05-16

写在前面

  本项目为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开始详述设计过程。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【数集项目之 MCDF】(一) 控制寄存器 control_register 的相关文章

  • 使用fescar遇到can not register RM,err:can not connect to fescar-server.

    前提 如果你看到了这篇文章 xff0c 说明你已经成功跑起了阿里爸爸fescar官方提供的example和server xff0c 并且你的客户端和服务端之间心跳正常 xff0c 但是当客户端进行事务操作时却提示以下错误 com span
  • 输入框限制输入20个中文字(40个字符)。eslint 报错\x00 no-control-regex解决

    需求是要限制用户输入的名称 xff0c 最多二十个中文字 xff0c 也就是40个字符 但我们平时使用str length来限制都是获取到字符串的长度而已 xff0c 并不能获取到具体的字符 这里使用正则来解决 一个汉字 61 2字节 61
  • Access-Control-Allow-Origin跨域解决及详细介绍

    首先 xff0c 跨域不是问题 是一种安全机制 这是你在开发时 上线前就必须提前考虑到的安全问题并且采取合适的手段去避免这个问题带来的程序错误 不过通常情况下 xff0c 前端开发的小伙伴们都非常坚信后端小伙伴的接口一定已经处理好了跨域这个
  • 解决了设置了Access-Control-Allow-Origin: *还是跨域的问题。

    说起跨域请求 大家首先想到的就会是设置请求头Access Control Allow Origin 但是有时候只设置这么一样还是解决不了的跨域问题就要分的比较细的设置请求头了 xff1a access control allow heade
  • Ajax请求Access-Control-Allow-Origin错误解决

    在JS中使用AJAX请求跨域时候 xff0c 会提示错误 Failed to load http localhost 8889 xxxxxxxxx No 39 Access Control Allow Origin 39 header is
  • tensorflow中control_flow_ops.while_loop

    self h0 61 tf zeros self batch size self hidden dim self h0 61 tf stack self h0 self h0 相当于 h0和C0 generator on initial r
  • Apollo control之PID算法

    Apollo studio 官网 xff1a Apollo开发者社区 baidu com 目录 1 PID简介 2 PID调参思路 3 代码 4 解决积分饱和的方法 4 1 IC 积分遇限削弱法 4 2 BC 反馈抑制抗饱和 1 PID简介
  • Pytorch中nn.Module中的self.register_buffer解释

    self register buffer作用解释 今天遇到了这样一种用法 xff0c self register buffer name Tensor xff0c 该方法的作用在于定义一组参数 该组参数在模型训练时不会更新 xff08 即调
  • sdf模型插入gazebo_ros_control插件

    gazebo ros control目前只支持老版的urdf模型 xff0c 官方教程 xff1a http gazebosim org tutorials tut 61 ros control sdf模型怎么办呢 xff1f 回答 xff
  • PX4 Position_Control RC_Remoter引入

    PX4飞控位置环控制中如何引入遥控器的控制量 本文基于PX4 1 12版本 相比于之前的版本 多引入了Flight Task这么一个模块 省流总结 遥控器的值通过 flight tasks update gt velocity setpoi
  • px4源码解读之fw_att_control

    目录 程序和控制流程源码解读总结 程序和控制流程 个人简单的总结了一下整个程序的流程如下 整个的控制流程图可以在官网中找到 源码解读 在解读源码之前 需要提几个公式 第一个就是协调转弯中的偏航控制 也就是流程图中为什么输入是空速 p 61
  • BlueROV-9: Driving Control

    Home location http python dronekit io guide vehicle state and parameters html The Home location isset when a vehicle fir
  • Promethues: swarm_control解读

    标签可以对节点分组 xff0c 具有 ns 属性 xff0c 可以让节点归属某个命名空间 lt group ns 61 34 iris 0 34 gt lt group ns 61 span class token string 34 ir
  • PX4 Offboard Control with MAVROS--Takeoff(一键起飞)

    警告 xff1a 请先在仿真环境下进行测试 xff0c 能达到预期效果后在进行实际飞行测试 xff0c 以免发生意外 本篇文章只是用作学习交流 xff0c 实际飞行时如出现意外情况作者不予以负责 所需材料 1 PIXhawk或者Pixrac
  • gazebo: ROS Control的仿真教程

    gazebo 43 ROS control 1 预备知识2 数据流3 实现动态避障的环境构建 本文主要介绍如何为仿真机器人做控制器的仿真 通过仿真控制器 xff0c 控制机器人的对应关节 1 预备知识 关于gazebo中机器人的仿真 xff
  • sip register超时和invite超时

    sip的register重传与超时 当发送第一个register时候 xff0c 开启定时器 xff0c 超过500ms没有响应 xff0c 重新发送 在发送的register 1s内没有响应 xff0c 在重发 xff0c 一致到32s的
  • 【MFC开发(16)】树形控件Tree Control

    1 树形控件的属性配置 xff08 1 xff09 Check Boxes xff1a 默认为false xff0c 如果选择为true的话每个节点前面会带有一个方框 xff08 2 xff09 Edit Labels xff1a 默认为f
  • 机器人独立关节PD控制(控制小白入门)

    通过今天的学习仿佛对机器人控制有了进一步了解 特记录下看书和抄相关代码笔记 参考书目如下 模型如下 推导出动力学方程如下 忽略重力 摩擦力及外界干扰 可以写成如下形式 不计重力 与上上张图片对比 得p的具体含义 此处p只用到p1 p2 p3
  • Apollo代码学习(六)—模型预测控制(MPC)

    Apollo代码学习 模型预测控制 前言 模型预测控制 预测模型 线性化 单车模型 滚动优化 反馈矫正 总结 前言 非专业选手 此篇博文内容基于书本和网络资源整理 可能理解的较为狭隘 起点较低 就事论事 如发现有纰漏 请指正 非常感谢 查看
  • 《现代控制系统》第五章——反馈控制系统性能分析 5.4 二阶系统里面极点以及零点带来的影响

    上一节图里面描绘的曲线 仅仅是针对阶跃响应为 的系统来说的 但是这给我们提供了一个很好的例子 许多系统拥有成对的主极点 我们可以通过类似上图的关系来估计系统的阶跃响应 这个方法尽管只是一个估算 但却能在避免拉普拉斯转化的情况下提供一个对超调

随机推荐