【芯片前端】保持代码手感——数据累加输出

简介: 【芯片前端】保持代码手感——数据累加输出

实现串行输入数据累加输出,输入端输入8bit数据,每当模块接收到4个输入数据后,输出端输出4个接收到数据的累加结果。输入端和输出端与上下游的交互采用valid-ready双向握手机制。要求上下游均能满速传输时,数据传输无气泡,不能由于本模块的设计原因产生额外的性能损失。


电路的接口如下图所示。valid_a用来指示数据输入data_in的有效性,valid_b用来指示数据输出data_out的有效性;ready_a用来指示本模块是否准备好接收上游数据,ready_b表示下游是否准备好接收本模块的输出数据;clk是时钟信号;rst_n是异步复位信号。


波形为:



顶层:

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
);
endmodule


答案解析

我最后提交的RTL呢,data_out是reg输出的,valid_b不是reg输出,后面也提交了一版valid_b reg输出的代码。


既然在累加四次的下一拍valid_b就必须要输出有效,那么可见这个题的核心就在于记录累加次数的计数器,所以我们就先做这个计数器好了:

wire hand_a = (valid_a && ready_a);
wire hand_b = (valid_b && ready_b);
//add num cnt
wire         cnt_en;
wire [3 -1:0]cnt_d;
wire [3 -1:0]cnt_q;
assign cnt_en = hand_a || hand_b;
assign cnt_d  = (hand_a && hand_b) ? 3'd1 :
        hand_b ? 3'd0 :
        cnt_q + 3'd1;
dffre #(.WIDTH(3)) u_cnt_dffre(
  .clk(clk),
  .rst_n(rst_n),
  .d(cnt_d),
  .en(cnt_en),
  .q(cnt_q)
);


这个cnt的寄存器位3bit,更新的条件必定是输入握手成功或输出握手成功,逻辑也很清晰:1.当只有输入握手时,cnt + 1;2.当只有输出握手时,cnt归零;3.当同一拍输入握手&&输出握手时,cnt置1,显然,在这种条件下是没有性能瓶颈的。


ok,cnt的条件已经做完,其他的就变得简单了。


累加寄存器的逻辑很类似,就不赘述了:

wire         value_en;
wire [10 -1:0]value_d;
wire [10 -1:0]value_q;
assign value_en = cnt_en;
assign value_d  = (hand_a && hand_b) ? {2'b0, data_in} :
          hand_b ? 10'd0 :
          value_q + {2'b0, data_in};
dffre #(.WIDTH(10)) u_value_dffre(
  .clk(clk),
  .rst_n(rst_n),
  .d(value_d),
  .en(value_en),
  .q(value_q)
);


进一步的,通过cnt_q的值来推到握手信号,对于valid_b,如果是逻辑输出的话可以如此:

assign valid_b  = (cnt_q == 3'd4);


如果要将valid_b作为寄存器输出可以这样:

wire valid_b_en = cnt_en;
wire valid_b_d  = (cnt_d == 3'd4);
dffre #(.WIDTH(10)) u_valid_b_dffre(
  .clk(clk),
  .rst_n(rst_n),
  .d(valid_b_d),
  .en(valid_b_en),
  .q(valid_b)
);

valid_b的输出时比较容易做的,对于ready_a则容易出错,误做为:


assign ready_a  = (cnt_q != 3'd4);

因为不能有空泡,所以输入的ready要看输出的握手,这样虽然性能更好,但是时序更差:


assign ready_a  = (cnt_q != 3'd4) || hand_b;

完整代码

`timescale 1ns/1ns
module dffre#(
  parameter WIDTH = 1
)(
  input         clk,
  input         rst_n,
  input  [WIDTH -1:0] d,
  input       en,
  output [WIDTH -1:0] q
);
reg [WIDTH -1:0]q;
always @(posedge clk or negedge rst_n)begin
  if(~rst_n)  q <= {WIDTH{1'b0}};
  else if(en) q <= d;
end
endmodule
module valid_ready(
  input         clk     ,   
  input         rst_n   ,
  input   [7:0] data_in   ,
  input       valid_a   ,
  input       ready_b   ,
  output        ready_a   ,
  output        valid_b   ,
  output      [9:0]   data_out
);
parameter MAX = 4;
wire hand_a = (valid_a && ready_a);
wire hand_b = (valid_b && ready_b);
//add num cnt
wire         cnt_en;
wire [3 -1:0]cnt_d;
wire [3 -1:0]cnt_q;
assign cnt_en = hand_a || hand_b;
assign cnt_d  = (hand_a && hand_b) ? 3'd1 :
        hand_b ? 3'd0 :
        cnt_q + 3'd1;
dffre #(.WIDTH(3)) u_cnt_dffre(
  .clk(clk),
  .rst_n(rst_n),
  .d(cnt_d),
  .en(cnt_en),
  .q(cnt_q)
);
//add num value
wire         value_en;
wire [10 -1:0]value_d;
wire [10 -1:0]value_q;
assign value_en = cnt_en;
assign value_d  = (hand_a && hand_b) ? {2'b0, data_in} :
          hand_b ? 10'd0 :
          value_q + {2'b0, data_in};
dffre #(.WIDTH(10)) u_value_dffre(
  .clk(clk),
  .rst_n(rst_n),
  .d(value_d),
  .en(value_en),
  .q(value_q)
);
//gen hand
wire valid_b_en = cnt_en;
wire valid_b_d  = (cnt_d == 3'd4);
dffre #(.WIDTH(10)) u_valid_b_dffre(
  .clk(clk),
  .rst_n(rst_n),
  .d(valid_b_d),
  .en(valid_b_en),
  .q(valid_b)
);
//assign valid_b  = (cnt_q == 3'd4);
assign ready_a  = (cnt_q != 3'd4) || hand_b;
assign data_out = value_q;
endmodule
相关文章
|
2月前
|
存储 监控 安全
前端框架的数据驱动方式如何保证数据的安全性?
总之,前端框架的数据驱动方式需要综合运用多种手段来保证数据的安全性。从传输、存储、访问控制到防范攻击等各个方面进行全面考虑和实施,以确保用户数据的安全可靠。同时,不断加强安全管理和技术创新,以应对不断变化的安全挑战。
116 60
|
2月前
|
缓存 前端开发 JavaScript
利用代码分割优化前端性能:策略与实践
在现代Web开发中,代码分割是提升页面加载性能的有效手段。本文介绍代码分割的概念、重要性及其实现策略,包括动态导入、路由分割等方法,并探讨在React、Vue、Angular等前端框架中的具体应用。
|
1月前
|
缓存 监控 前端开发
探索前端性能优化:关键策略与代码实例
本文深入探讨前端性能优化的关键策略,结合实际代码示例,帮助开发者提升网页加载速度和用户体验,涵盖资源压缩、懒加载、缓存机制等技术。
|
2月前
|
Web App开发 缓存 监控
前端性能优化实战:从代码到部署的全面策略
前端性能优化实战:从代码到部署的全面策略
40 1
|
2月前
|
Web App开发 前端开发 JavaScript
前端性能优化实战:从代码到部署的全面指南
前端性能优化实战:从代码到部署的全面指南
45 1
|
2月前
|
前端开发 JavaScript
前端界的革命:掌握这些新技术,让你的代码简洁到让人惊叹!
前端技术的快速发展带来了许多令人惊叹的新特性。ES6及其后续版本引入了箭头函数、模板字符串等简洁语法,极大减少了代码冗余。React通过虚拟DOM和组件化思想,提高了代码的可维护性和效率。Webpack等构建工具通过模块化和代码分割,优化了应用性能和加载速度。这些新技术正引领前端开发的革命,使代码更加简洁、高效、可维护。
34 2
|
2月前
|
前端开发 JavaScript 测试技术
前端工程师的必修课:如何写出优雅、可维护的代码?
前端工程作为数字世界的门面,编写优雅、可维护的代码至关重要。本文从命名规范、模块化设计、注释与文档、遵循最佳实践四个方面,提供了提升代码质量的方法。通过清晰的命名、合理的模块划分、详细的注释和持续的学习,前端工程师可以写出高效且易于维护的代码,为项目的成功打下坚实基础。
41 2
|
2月前
|
监控 前端开发 JavaScript
前端开发的终极奥义:如何让你的代码既快又美,还不易出错?
【10月更文挑战第31天】前端开发是一个充满挑战与机遇的领域,本文从性能优化、代码美化和错误处理三个方面,探讨了如何提升代码的效率、可读性和健壮性。通过减少DOM操作、懒加载、使用Web Workers等方法提升性能;遵循命名规范、保持一致的缩进与空行、添加注释与文档,让代码更易读;通过输入验证、try-catch捕获异常、日志与监控,增强代码的健壮性。追求代码的“快、美、稳”,是每个前端开发者的目标。
43 3
|
2月前
|
前端开发 JavaScript 开发者
前端开发的终极技巧:如何让你的代码既简洁又高效,还能减少bug?
【10月更文挑战第30天】前端开发充满挑战与创新,如何编写简洁高效且少bug的代码是开发者关注的重点。本文介绍五大技巧:1. 模块化,提高代码复用性;2. 组件化,降低代码耦合度;3. 使用现代框架,提高开发效率;4. 统一代码规范,降低沟通成本;5. 利用工具,优化代码质量。掌握这些技巧,让前端开发更高效。
113 1
|
2月前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
49 1