透过一个例子加深理解阻塞和非阻塞赋值

透过一个例子加深理解阻塞和非阻塞赋值


非阻塞: <=
阻塞: =

题目

异步时钟域数据复用设计

1、相关的输入输出信号及时序关系:
在这里插入图片描述
图中的TS_IN[7:0]、CLK、SYNC分别为TS传输流的数据信号、字节时钟、同步信号。时序图如下:
在这里插入图片描述

TS传输流的基本单元是帧结构,分为数据帧和空帧。假设每帧包含10个字节,第一个字节为同步字节,即H“FF”;空帧的标志是第二字节和第三字节全为H“EE”。

DIN[7:0]、CLK_W、EN分别是需要复用的控制数据、相应的字节时钟和数据使能。时序图如下:
在这里插入图片描述
RESET是系统的复位信号。
TS_OUT[7:0]是复用了DIN数据的TS传输流,码率与输入TS传输流相同。

注意:时钟CLK与CLK_W是异步的。本设计假定为CLK为10MHz,CLK_W为3MHz。

2、设计要求:假设TS传输流中的空帧足够多,要求将某些空帧的数据区(共7个数据)全部换为数据DIN(帧同步字节和空帧标志不变),按照TS传输流格式进行传输。TS传输流数据帧中的数据和DIN数据不能出现丢失。

程序

顶层

module top_data_mux
    (
		  input   			rst_n,
		  
          input   			clk_10m,
		  input   [7:0]	    ts_in,
		  input	 			sync,
		  
		  input   			clk_3m,
		  input   [7:0]	    din,
		  input   			en,
		  
          output  [7:0]     ts_out
    );
   
wire	[7:0]	q;
wire 			rdreq;

fifo u0_fifo
(
		.q		(q),
		.data	(din),
		.wrreq	(en),
		.wrclk	(clk_3m),
		.rdreq	(rdreq),
		.rdclk	(clk_10m)
);

ts_control u0_ts_control
(
      .ts_out	(ts_out),
		.rdreq	(rdreq),
		.q		(q),
		.ts_in	(ts_in),
		.clk_10m (clk_10m),
		.rst_n	(rst_n),
		.sync	(sync)
);
endmodule 

ts_control模块

module  ts_control
    (
          input               clk_10m,
          input               rst_n,
		  input               sync,
          input       [7:0]   ts_in,
		  input       [7:0]   q,

		  output  reg         rdreq,
		  output      [7:0]   ts_out
//        output  reg [7:0]   ts_out
    );

	 
//reg    [3:0]  cur_state   ;           
reg    [3:0]  next_state  ;                   
reg    [3:0]  cnt  ; 
reg			  swich_en;
reg			  cnt_en;

	 
localparam  s1     = 4'b0001;
localparam  s2     = 4'b0010; 
localparam  s3     = 4'b0100; 
localparam  s4     = 4'b1000; 

//assign    rdreq = (next_state == s4)? 1'b1:1'b0 ;
assign    ts_out = (swich_en == 1'b1)? q : ts_in ;

//(三段式状态机)同步时序描述状态转移
//always @(posedge clk_10m or negedge rst_n) begin
//    if(rst_n == 1'b0)
//        cur_state <= s1;
//    else
//        cur_state <= next_state;
//end

always @(posedge clk_10m or negedge rst_n) begin
    if(rst_n == 1'b0) begin
	     next_state<= s1  ;
        cnt_en		<= 1'b0;
        rdreq    	<= 1'b0;
		  swich_en	<= 1'b0;
	 end
	 else begin	  
        case(next_state)
         s1: begin
					if(ts_in==8'hff && sync==1'b1)
						next_state <= s2;
					else 
						next_state <= s1;
				 end
			s2: begin
					if(ts_in == 8'hee)begin
						next_state <= s3;
//						rdreq      <= 1'b1;
						end
					else 
						next_state <= s1;
				 end
		 	s3: begin
					if(ts_in == 8'hee)begin
						next_state <= s4;
						rdreq      <= 1'b1;
						cnt_en     <= 1'b1;
//						swich_en   <= 1'b1;
						end
					else 
						next_state <= s1;
				 end
			s4: begin
//			      swich_en   <= 1'b1;
					if(cnt == 4'd6)begin
						rdreq      <= 1'b0;
						cnt_en     <= 1'b0;
						next_state <= s1;
						end
//					else if(cnt == 4'd7)begin
//                  next_state <= s1;
//						swich_en   <= 1'b0;
//						end
					else 
						next_state <= s4;
				 end
			default : ;
			endcase
	 end
end

//always @(posedge clk_10m or negedge rst_n)
//begin
//	if(!rst_n) 			
//		ts_out <= 8'h00;
//	else if(swich_en) 	
//		ts_out <= q ;
//	else 				
//		ts_out <= ts_in ;
//end

always @(posedge clk_10m or negedge rst_n)
begin
	if(!rst_n) 
		swich_en <= 1'd0;
	else if(cnt <= 4'd6 && next_state == s4)
		swich_en <= 1'd1;
	else 
		swich_en <= 1'd0;
end	 
	 

always @(posedge clk_10m or negedge rst_n)
begin
	if(!rst_n) 
		cnt <= 4'd0;
	else if(cnt_en == 1'b1)
		cnt <= cnt + 4'b1;
	else 
		cnt<=4'd0;
end	 
	 
endmodule 

仿真

在这里插入图片描述

分析

<=赋值是把时钟上升沿前时刻的数据值作为,时钟上升沿时刻的数据值

ts_in在输入0xff之后,next_state的值立马变成0010,但是在0xff的这个周期内,其他采用<=赋值方法采样到的还是0001。之前我一直理解的是<=赋值会在下一个clk才生效,即在0xff的这个时间段next_state还是0001,这样理解会使对周期时序要求严格的程序产生错误。

在s3状态时,检测到了0xee后,rdreq和cnt_en被立马置1,但是其他采用<=赋值方法的模块是采不到rdreq和cnt_en为1,要到下一个clk才能采到。所以对于fifo模块,rdreq被置1的第一个clk时期,fifo其实是没有读到rdreq为1,第二个clk时,fifo收到了rdreq,立马输出了第一个数据,可以把它理解成<=赋值,虽然立马输出了第一个数据,但是其他模块读到的还是输出之前的数据,不信的话可以自己仿真试试。对于这个题目而言,要马上采到fifo的输出数据,补到ts_out上,不然结果有问题。所以为了其他模块能够采到fifo立马输出的这个数据,采用=赋值。保证swich_en == 1’b1的时刻,正好输出第一个q就行。

assign ts_out = (swich_en == 1’b1)? q : ts_in ;

swich_en 置1条件cnt <= 4’d6 && next_state == s4 。 虽然在检测到第二个0xee时,next_state就是s4了,但是由于采用<=赋值;且这个判断条件

cnt <= 4’d6 && next_state == s4

处于一个<=赋值的模块。但凡这两个条件中有一个是=赋值,都能在next_state 等于 s4 的当个周期让swich_en 置1,所以程序中swich_en的置1,在next_state 等于 s4 的第二个clk。

同样的,可以自己理解一下cnt和cnt_en之间的关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值