数字集成电路设计-19-pipeline的写法

引言

之前,我们介绍了数字设计中一些基本组合逻辑的写法(http://blog.csdn.net/rill_zhen/article/details/39586191)以及状态机的写法(http://blog.csdn.net/rill_zhen/article/details/39585367),本小节我们通过一个小实验来熟悉一下pipeline的写法。

在多数的资料和教课书中提到pipeline时,大多只是解释概念,很少介绍其具体RTL实现的,给人一种高达上的感觉。有的资料中会提到具体写法,但大多采用pipe_ready、pipe_hold信号来控制流水线的暂停和继续。

那种写法在流水线较简单时,一旦流水线变得复杂,尤其是有些stage还包含子流水线时,pipe_ready/pipe_hold的逻辑就变得很杂乱,以致容易出错。本小节我们介绍另外一种写法,将valid/ready协议和pipeline结合在一起。

关于valid/ready协议,我们之前已经介绍过了,请参考(http://blog.csdn.net/rill_zhen/article/details/44219593)。

将每个stage都解耦合,认为是独立的逻辑单元,所有stage只和自己的上一级和下一级交互,并且采用valid/ready握手协议进一步解耦合。这样设计的pipeline,不仅界限清晰,接口简介,耦合度低。便于以后的扩展,debug起来也很容易定位问题。

1,代码清单

下面我们设计一个3级全流水模块,采用上述思路进行编码。

pipeline.v:

/*
* pipeline example
* Rill 2015-05-11
*/

module Mpipeline
(
	input clk,
	input rst_n,

	input en_i,
	input [7:0] data_i,

	output en_o,
	output [7:0] data_o,

	output idle
);

	wire rdy_pb2pa;
	wire vld_pa2pb;
	wire [7:0] data_pa2pb;

	wire rdy_pc2pb;
	wire vld_pb2pc;
        wire [7:0] data_pb2pc;

	wire rdy_pa;

	Mpa pa
	(
	.clk (clk),
	.rst_n (rst_n),
	.valid_i (en_i),
	.data_i (data_i),
	.ready_i (rdy_pb2pa),
	.ready_o (rdy_pa),
	.valid_o (vld_pa2pb),
	.data_o (data_pa2pb)
	);

	Mpb pb
	(
	.clk (clk),
	.rst_n (rst_n),
	.valid_i (vld_pa2pb),
	.data_i (data_pa2pb),
	.ready_i (rdy_pc2pb),
	.ready_o (rdy_pb2pa),
	.valid_o (vld_pb2pc),
	.data_o (data_pb2pc)
	);

	Mpc pc
	(
	.clk (clk),
	.rst_n (rst_n),
	.valid_i (vld_pb2pc),
	.data_i (data_pb2pc),
	.ready_i (1‘b1),
	.ready_o (rdy_pc2pb),
	.valid_o (en_o),
	.data_o (data_o)
	);

   assign idle = ~vld_pa2pb & ~vld_pb2pc & ~en_o;

endmodule

module Mpa
(
	input clk,
	input rst_n,

	input 			valid_i, //from pre-stage
	input [7:0] 	data_i, //from pre-stage
	input 			ready_i, //from post-stage

	output 			ready_o,//to pre-stage

	output 			valid_o, //to post-stage
	output [7:0]	data_o //to post-stage
);

	reg 		valid_o_r;
	reg [7:0] 	data_o_r;

        wire [7:0]	calc;

	assign calc = data_i + 1‘b1;

	always @(posedge clk)
		if(~rst_n)
			valid_o_r <= 1‘b0;
		else if(valid_i)
			valid_o_r <= 1‘b1;
		else if(~valid_i)
			valid_o_r <= 1‘b0;

	always @(posedge clk)
		if(~rst_n)
			data_o_r <= 8‘b0;
		else if(valid_i)
			data_o_r <= calc;

	assign ready_o = ready_i;
	assign valid_o = valid_o_r;
	assign data_o = data_o_r;
endmodule

module Mpb
(
	input clk,
	input rst_n,

	input 			valid_i, //from pre-stage
	input [7:0] 	data_i, //from pre-stage
	input 			ready_i, //from post-stage

	output 			ready_o,//to pre-stage

	output 			valid_o, //to post-stage
	output [7:0]	data_o //to post-stage
);

	reg 		valid_o_r;
	reg [7:0] 	data_o_r;

        wire [7:0]	calc;

	assign calc = data_i << 1‘b1;

	always @(posedge clk)
		if(~rst_n)
			valid_o_r <= 1‘b0;
		else if(valid_i)
			valid_o_r <= 1‘b1;
		else if(~valid_i)
			valid_o_r <= 1‘b0;

	always @(posedge clk)
		if(~rst_n)
			data_o_r <= 8‘b0;
		else if(valid_i)
			data_o_r <= calc;

	assign ready_o = ready_i;
	assign valid_o = valid_o_r;
	assign data_o = data_o_r;
endmodule

module Mpc
(
	input clk,
	input rst_n,

	input 			valid_i, //from pre-stage
	input [7:0] 	data_i, //from pre-stage
	input 			ready_i, //from post-stage

	output 			ready_o,//to pre-stage

	output 			valid_o, //to post-stage
	output [7:0]	data_o //to post-stage
);

	reg 		valid_o_r;
	reg [7:0] 	data_o_r;

        wire [7:0]	calc;

	assign calc = data_i - 1‘b1;

	always @(posedge clk)
		if(~rst_n)
			valid_o_r <= 1‘b0;
		else if(valid_i)
			valid_o_r <= 1‘b1;
		else if(~valid_i)
			valid_o_r <= 1‘b0;

	always @(posedge clk)
		if(~rst_n)
			data_o_r <= 8‘b0;
		else if(valid_i)
			data_o_r <= calc;

	assign ready_o = ready_i;
	assign valid_o = valid_o_r;
	assign data_o = data_o_r;
endmodule

tb.v:

/*
* pipeline example
* Rill 2015-05-11
*/

module Ttb;
	reg clk;
	reg rst_n;
	reg en_i_r;
	reg [7:0] data_i_r;

	wire en_o;
	wire [7:0] data_o;
	wire idle;

	Mpipeline pipeline
	(
	.clk (clk),
	.rst_n (rst_n),
	.en_i (en_i_r),
	.data_i (data_i_r),
	.en_o (en_o),
	.data_o (data_o),
	.idle (idle)
	);

	initial
		begin
			clk = 1‘b0;
			rst_n = 1‘b0;
			en_i_r = 1‘b0;
			data_i_r = 8‘b0;

			fork
				forever #5 clk = ~clk;
			join_none

			repeat(10) @(posedge clk);
			rst_n = 1‘b1;
			repeat(10) @(posedge clk);

			@(posedge clk);
			en_i_r <= 1‘b1;
			data_i_r <= 8‘h1;

			@(posedge clk);
			en_i_r <= 1‘b1;
			data_i_r <= 8‘h2;

			@(posedge clk);
			en_i_r <= 1‘b1;
			data_i_r <= 8‘h3;

			@(posedge clk);
			en_i_r <= 1‘b1;
			data_i_r <= 8‘h4;

		        @(posedge clk);
			en_i_r <= 1‘b0;
			data_i_r <= 8‘h0;
			repeat(10) @(posedge clk);
			$finish();
		end
endmodule

2,脚本

pp.sh

#! /bin/bash

#
# pp.sh
# usage: ./pp.sh c/w/r
# Rill create 2014-09-03
#

TOP_MODULE=Ttb

export SRC_DIR=$(pwd)
tcl_file=run.tcl

if [ $# != 1 ];then
echo "args must be c/w/r"
exit 0
fi

if [ $1 == "c" ]; then
echo "compile lib..."
ncvlog -f ./vflist -sv -update -LINEDEBUG;
ncelab -delay_mode zero -access +rwc -timescale 1ns/10ps ${TOP_MODULE}
exit 0
fi

if [ -e ${tcl_file} ];then
rm ${tcl_file} -f
fi
touch ${tcl_file}

if [ $1 == "w" ];then
echo "open wave..."
echo "database -open waves -into waves.shm -default;" >> ${tcl_file}
echo "probe -shm -variable -all -depth all;" >> ${tcl_file}
echo "run" >> ${tcl_file}
echo "exit" >> ${tcl_file}
fi

if [ $1 == "w" -o $1 == "r" ];then
echo "sim start..."
ncsim  ${TOP_MODULE} -input ${tcl_file}
fi

echo "$(date) sim done!"

vflist:

-incdir ${SRC_DIR}

${SRC_DIR}/pipeline.v
${SRC_DIR}/tb.v

3,仿真结果

4,扩展

上面是一个全流水pipeline,所以所有stage的valid只要有输入就会拉高,ready信号只要下一stage的ready有效就拉高(能接收新数据)。

在实际的工作中,将calc信号换成组合逻辑云,正确处理valid_o和ready_o,即可。

5,小节

不知道pipeline还有没有更好的写法。

时间: 2024-12-19 18:38:19

数字集成电路设计-19-pipeline的写法的相关文章

数字集成电路设计-12-状态机的四种写法

引言 在实际的数字电路设计中,状态机是最常用的逻辑,而且往往是全部逻辑的核心部分,所以状态机的质量,会在比较大的程度上影响整个电路的质量. 本小节我们通过一个简单的例子(三进制脉动计数器)来说明一下状态机的4中写法. 1,模块功能 由于我们的目的在于说明状态机的写作方式,所以其逻辑越简单有利于理解.就是一个简单的脉动计数器,每个三个使能信号输出一个标示信号. 2,一段式 状态机的写法,一般有四种,即一段式,两段式,三段式,四段式.对于一段式的写法,整个状态机的状态转移.转移条件.对应状态的输出都

数字集成电路设计-20-multi-cycle

引言 前面我们介绍了流水线的写法(http://blog.csdn.net/rill_zhen/article/details/45980039),流水线是数字设计中很常用的一种设计方法,可以提高运行频率,提高吞吐量. 如果组合逻辑延迟较大,一个时钟周期完成不了时,除了插入寄存器将组合逻辑拆分成流水线外,还可以采用multi-cycle的方式. multi-cycle的工作机制很简单,从给定输入之后,等待多个周期之后,再去采样输出结果. 本小节我们将通过一个小实验来说明multi-cycle的具

数字集成电路设计-16-关于AXI协议

引言 AXI协议有可能是我们平时电路设计时经常遇到的一个协议,也是一个不错的协议,本小节我们就来熟悉一下. 乍一看,AXI协议的信号众多,眼花缭乱,容易发蒙.但其实其基本思想很简单.只要掌握以下几点: 1,valid/ready协议 axi协议是典型的基于valid/ready协议的总线协议.valid/ready协议的优势就是master和slave的相对独立性比较好.对于一次传输,作为master的发起方不用检查salve是否准备好,就可以将传输内容放到总线上:同样对于接收方的slave来说

数字集成电路设计经验技巧分享

废话不多说,直接贴出电路及电路设计经验技巧大合集84个资料的文件列表,太多了,只显示一部分吧,有需要的朋友可以到闯客网技术论坛下载,同时可以加入我们的技术交流裙:613377058,无偿共享,在线解答各种技术问题.资料链接:https://bbs.usoftchina.com/thread-206874-1-1.html 文件列表:BUCKBOOST电路原理分析.docxCAN总线接口电路设计注意事项.docxDC-DC升压电路.docxFPGACPLD数字电路设计经验分享.docxMIC电路工

数字集成电路设计-13-常用模块集锦

引言 C语言,C++语言等软件编程语言吸引我们的一个很重要的原因是他们都能提供非常丰富的函数库供我们使用,大大提高coding的效率. 但是像verilogHDL等HDL语言这方面做的比较弱,尤其是可综合的语法,基本没有通用的模块库供我们使用,所以编码效率会比较低.如果我们把平时经常使用的一些模块积累起来,慢慢的标准化,这样以后我们再设计新的电路时,就会方便很多,今天就是开始. 1,判断两个信号是否相等 function Fcompare; input valid_a,valid_b; inpu

数字集成电路设计-18-UVM

引言 UVM(Universal Verification Methodology)可以理解为形而上的东西,可以理解为是基于System verilog的一个库,提供一些API调用. 其实没必要把UVM抬的那么高,上升到形而上的层次.因为在实际的IC验证时,对某个复杂DUT的验证时,一般都会拆分成那几个模块. 要对DUT测试,肯定需要先产生测试用例,就是UVM中的sequencer和sequence概念. 产生测试用例之后,肯定需要把测试用例送到DUT端口上,作为激励,就是UVM中的driver

国家明确规划重点软件和集成电路设计领域

关于印发国家规划布局内重点软件和集成电路设计领域的通知 发改高技[2016]1056号 各省.自治区.直辖市及计划单列市发展改革委.工业和信息化主管部门.财政厅(局).国家税务局.地方税务局: 为贯彻落实<国务院关于印发进一步鼓励软件产业和集成电路产业发展若干政策的通知>(国发[2011]4号),按照财政部.国家税务总局.发展改革委.工业和信息化部<关于软件和集成电路产业企业所得税优惠政策有关问题的通知>(财税[2016] 49号)要求,现就国家规划布局内重点软件和集成电路设计领域

集成电路设计流程分工

推荐一下本人的原创博客专栏:SoC嵌入式软件架构设计 谢谢! 正规的集成电路设计公司在进行片上系统(SoC)设计时都有明确的岗位分工,甚至会以部门的形式来区分各部分的职责,而且很多时候集成电路设计公司还会提供整体解决方案,包括芯片.软件和硬件,生产商直接按这个方案买其他的电阻电容等元器件即可生产.测试和销售.整体解决方案分工如下: 1.  市场:负责产品规格调研.产品规划.产品经理负责项目立项. 2.  System design系统设计:制定产品规格,系统设计,模块级的FPGA验证. 3.  

Tanner Tools v16 Win64 1CD集成电路设计环境

Tanner Tools Pro是一套以布局为主的软体(L-Edit, L-Edit/DRC, L-Edit/Extract),配合电路图的绘图输入软体(S-Edit) 与电路层次的模拟软体(T-Spice ),构成了一套IC设计系统. Tanner Tools Pro工具,它可提供完整的集成电路设计环境,帮助初学者进入VLSI设计领域.  Tanner Tools Pro工具非常 适合初学者学习,它从电路图设计.电路分析仿真到电路布局环境一应俱全.本书针对VLSI设计实习课程设计多个实验,读