EDA365电子论坛网
标题:
multi-cycle
[打印本页]
作者:
haidaowang
时间:
2020-9-4 16:30
标题:
multi-cycle
引言
9 B( C2 L, l# [& X
前面我们介绍了流水线的写法(
pipeline的写法
),流水线是数字设计中很常用的一种设计方法,可以提高运行频率,提高吞吐量。
0 u3 v! [8 t' e% {& W9 R
6 V) R. j: k D% V/ P2 W j5 Y4 ^
如果组合逻辑延迟较大,一个时钟周期完成不了时,除了插入寄存器将组合逻辑拆分成流水线外,还可以采用multi-cycle的方式。
9 W0 ?! o3 _" c) W: |
6 @+ S9 s ?' O: }
multi-cycle的工作机制很简单,从给定输入之后,等待多个周期之后,再去采样输出结果。
$ f+ A1 J$ W3 _3 t4 r$ ~' J* b" D! j
3 U) u0 ]6 o! c! X, X: [1 r. [; ^- Z
本小节我们将通过一个小实验来说明multi-cycle的具体RTL实现。
& v6 a3 p9 D! |4 M
5 U9 t8 Y8 B! c6 T- @: X
; U; _( L% B4 }$ a6 u+ e9 D
3 `7 Z8 E5 `& E1 e
1,功能介绍
+ t- y6 \5 k2 o- F6 u+ Y
假设有某个模块,其计算量很大,以致延迟较大,一个周期完成不了,需要3个cycle才行。
2 b, @$ @5 j# h0 y. y4 h/ h$ r& A
' o. q7 y e+ q: w* n7 C. e
假设时钟周期是10,这个模块的运算分为“加法,左移,减法”三个操作,分别用时7,8,9。
, q) o' p- x% ?) j' j
* e! A9 v: k2 G0 n
8 B# D: O+ k! T$ W, o7 F- ^$ A
3 n8 Y! ^" o; S7 G! R6 m
2,RTL实现
( Q F2 t- \/ u3 u
1 z. s" w; v# s9 h/ h- w) ^
如果在数字设计时,遇到上述模块描述的情况时,可以考虑multi-cycle实现。
; ]0 ^* S! T% F8 Y
- x) O0 i% G9 d( s6 W) j
具体RTL如下:mc.v
& k5 I! ?5 K3 T K4 h. r6 ]
- r0 @% I* T& i( O- E7 N5 g
其中关于状态机的写法,我们之前有专门介绍,如有疑问,请参考(
你知道状态机的四种写法都是什么吗?
)。
7 z B( ?$ N. S- w( c
4 {- D2 }6 i! ^
/*
* multi-cycle example
* Rill 2015-05-29
*/
! j' g, i! r- Z; k
module Mmulti_cycle
(
input clk,
input rst_n,
input en_i,
input [7:0] data_i,
output en_o,
output [7:0] data_o,
output idle
);
5 O# w1 R, d* ~8 @' K+ F9 e
//===================
// control path, fsm
//===================
& X$ l0 R- C: X w5 ~3 o) f/ B
localparam S_IDLE = 4'd0;
localparam S_CYCLE1 = 4'd1;
localparam S_CYCLE2 = 4'd2;
localparam S_CYCLE3 = 4'd3;
reg [3:0] c_state_r;
wire [3:0] n_state;
wire state_changed;
wire cs_idle = (c_state_r == S_IDLE);
wire cs_cycle1 = (c_state_r == S_CYCLE1);
wire cs_cycle2 = (c_state_r == S_CYCLE2);
wire cs_cycle3 = (c_state_r == S_CYCLE3);
wire ns_idle = cs_cycle3;
wire ns_cycle1 = cs_idle & en_i;
wire ns_cycle2 = cs_cycle1;
wire ns_cycle3 = cs_cycle2;
assign state_changed = ns_idle | ns_cycle1 | ns_cycle2 | ns_cycle3;
assign n_state = ( {4{ns_idle}} & S_IDLE
| {4{ns_cycle1}} & S_CYCLE1
| {4{ns_cycle2}} & S_CYCLE2
| {4{ns_cycle3}} & S_CYCLE3
);
always @(posedge clk)
if(~rst_n)
c_state_r <= S_IDLE;
else
c_state_r <= n_state;
//=================
// data path,calc
//=================
wire [7:0] data1;
wire [7:0] data2;
wire [7:0] data3;
assign #7 data1 = data_i + 1'b1;
assign #8 data2 = data1 << 1'b1;
assign #9 data3 = data2 - 1'b1;
assign en_o = cs_cycle3;
assign data_o = data3;
assign idle = cs_idle;
endmodule
- h: y) Z! p/ L2 Y, y
+ @* s. s7 n" |3 ~7 |- l
) g/ W( K% h* V% h* ~" c
3,testbench
# l2 O) J9 ?2 Q; ?7 M
: x/ Y7 G' B6 c4 D! w" X% V
具体multi-cycle模块是如何工作的呢,我们需要写个简单的TB验证一下:tb.v
8 {2 ~$ l: N, C
' \* y6 n) `9 u- Z0 h4 h f
/*
* multi-cycle example
* Rill 2015-05-29
*/
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;
Mmulti_cycle mc0
(
.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;
repeat(10) @(posedge clk);
$finish();
end
endmodule
; v$ Y' P+ Y4 `6 J7 k$ ^6 q
4 \4 B/ V! \9 Q8 D# f0 q
' O4 r: V) u# L9 z" Z8 \% f7 K
; {+ v( R* B: a% u$ C5 u
1 ^1 Q8 h: ~( q2 b! j0 U
4,nc脚本和vflist
8 q+ P7 T; n( Z. w2 U+ m( U
, j3 n: X0 d, k
mc.sh:
" v7 j& |) @2 Z9 w8 f, U% B6 M. P/ y
% p y D. g( p# n. q1 a/ t
#! /bin/bash
5 Q$ O; }: c6 f. P# K c
# P; u) x# C1 ?. Y8 f- x
#
# mc.sh
# usage: ./mc.sh c/w/r
# Rill create 2014-09-03
#
( s- m6 q% @/ h- r0 S* N c
4 b" @5 W6 v2 x+ o) m) z
TOP_MODULE=Ttb
4 Y9 Y9 O1 x5 }7 U/ `3 L
export SRC_DIR=$(pwd)
tcl_file=run.tcl
; G# W" S: c2 @7 _" @. N! \9 Z
if [ $# != 1 ];then
echo "args must be c/w/r"
exit 0
fi
j( D" Z% H g' y. {" `
if [ $1 == "c" ]; then
echo "compile lib..."
ncvlog -f ./vflist -sv -update -LINEDEBUG;
#ncelab -delay_mode zero -access +rwc -timescale 1ns/10ps ${TOP_MODULE}
ncelab -delay_mode distribute -access +rwc -timescale 1ns/10ps ${TOP_MODULE}
exit 0
fi
' N' g6 H/ H( K, F# j, R
5 I5 Z" t% T. Q, E; ?$ r3 ?: x
if [ -e ${tcl_file} ];then
rm ${tcl_file} -f
fi
touch ${tcl_file}
, N9 J0 _ I. z/ c7 o( _
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
5 n/ @+ K2 {! o8 l; [& e! R
if [ $1 == "w" -o $1 == "r" ];then
echo "sim start..."
ncsim ${TOP_MODULE} -input ${tcl_file}
fi
" J0 _7 o2 l- y0 ]2 X0 r$ W& F- e
echo "$(date) sim done!"
2 k: e4 q& E6 x
( J# }+ ~# _. Q; s- A
4 m% F$ i3 s9 O( V+ g( ~# z
vflist:
- j7 Y% Z9 C3 w: Z @9 Z1 ^
! x9 C3 N% y" P% r+ y0 G2 ^
-incdir ${SRC_DIR}
( |7 k& ^$ P6 ~+ q2 J( `
${SRC_DIR}/mc.v
${SRC_DIR}/tb.v
: [5 Z) ]6 C$ J$ R6 h7 E
& F, S, ~7 r/ Q; H5 P! n
# R/ |& |" V; N7 w: K+ @3 s: v* O
n3 s: q4 R! P+ e. J2 |8 y
5,验证
8 M: }- q' y" U! G; C2 N
2 s* z0 J# O8 M; X. c
运行mc.sh c; mc.sh w即可得到仿真波形:
" m$ X, P! ^% y* A2 E* B
# U& a9 m' W) Z
1.png
(146.59 KB, 下载次数: 2)
下载附件
保存到相册
2020-9-4 16:28 上传
2 `' _1 P6 `8 m
i: h& a- n# `9 f/ @6 k; E
6 z& ~, Z5 f6 ~& {: |
通过波形可以看出,mc模块在经过3个cycle之后输出了运算结果3。
( D6 ~+ e3 H- [; g" @6 h
# y# {- {6 O4 V6 y$ }) ^, I9 [3 q
& @3 h" N1 K: w% Q6 G/ ?
- G' U3 J8 x* k% ^/ v
6,小结
( c2 r* p, q0 O% p7 t; P
" b- ~4 y4 h, s
pipeline和multi-cycle是处理长延迟逻辑常用的两种方式,我们都介绍过了。
) h7 F% O0 w5 J- a5 w
! C/ J/ C5 I: e: m" e
Enjoy!
- F8 W9 a& w B5 v6 N l" |& z+ s
6 d* O# C' E4 s1 V4 Y/ ]3 F
作者:
younicp
时间:
2020-9-4 17:25
multi-cycle
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2