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

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

实现串行输入数据累加输出,输入端输入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
相关文章
|
23天前
|
前端开发 小程序 Java
uniapp上传图片 前端以及java后端代码实现
uniapp上传图片 前端以及java后端代码实现
34 0
|
26天前
|
缓存 前端开发
前端代码整洁与规范之CSS篇
【4月更文挑战第2天】 前端代码整洁与规范之CSS篇
43 4
|
2月前
|
JSON 前端开发 Java
layui上传图片,前端直接拷代码,后端……
layui上传图片,前端直接拷代码,后端……
31 0
|
2月前
|
缓存 前端开发 JavaScript
揭秘前端性能优化:从代码到用户体验的全面升级
揭秘前端性能优化:从代码到用户体验的全面升级
20 0
|
3月前
|
前端开发 JavaScript 安全
从前端性能优化角度谈JavaScript代码压缩与混淆
本文从前端性能优化的角度出发,探讨了JavaScript代码压缩与混淆的重要性及实现方式,通过分析不同压缩混淆工具的特点和效果,为开发者提供了实用的指导和建议。
|
4天前
|
SQL 前端开发 JavaScript
前端vite+vue3结合后端node+koa——实现代码模板展示平台(支持模糊搜索+分页查询)
前端vite+vue3结合后端node+koa——实现代码模板展示平台(支持模糊搜索+分页查询)
19 4
|
14天前
|
存储 缓存 前端开发
前端如何利用indexDB进行数据优化
使用IndexedDB作为浏览器内置的客户端数据库,用于存储大量数据和实现离线支持。它能缓存常用数据,减少服务器请求,提高用户体验。IndexedDB支持数据索引、复杂查询及版本管理,允许离线操作并同步到服务器。但需熟悉其异步API,可借助Dexie.js、localForage等库简化使用。
|
15天前
|
前端开发 JavaScript 算法
比较流行的前端代码书写规范都有哪些
【4月更文挑战第13天】前端代码规范增进代码可读性和团队协作,包括缩进(用2空格)、命名(变量 camelCase,常量 MY_CONSTANT,类 PascalCase)、注释、语句与表达式、错误处理、代码复用。文件命名规范涉及扩展名、目录结构、简洁文件名、入口文件和配置文件命名。遵循这些规范能提高代码一致性,但需按项目需求调整。不断学习新规范以适应前端技术发展。
18 1
|
17天前
|
监控 前端开发 JavaScript
如何使用浏览器调试前端代码?
【4月更文挑战第11天】前端开发中,浏览器调试是关键技能,能提升代码质量。本文介绍了如何使用浏览器的调试工具:1) 打开调试窗口(F12或右键检查);2) Elements标签页检查DOM结构和样式;3) Console调试JavaScript,查看日志和错误信息;4) Sources设置断点调试JS文件;5) 利用Network、Performance和Memory等标签页优化性能。熟悉调试工具、利用日志和错误信息能有效定位问题,提高开发效率。
42 7
|
28天前
|
前端开发 JavaScript UED
【前端】javascript+html+css 家具销售网站(代码+报告)
【前端】javascript+html+css 家具销售网站(代码+报告)