项目实战-UART模块设计及验证1.

设计核心内容:

uart模块,包含tx/rx两个部分:

module uart(
	input			clk,
	input			rstn,
//tx	
	input	[7:0]	tx_data,
	input			tx_data_valid,
	output			tx_ready,
	output			tx,
//rx
	input			rx,
	output	[7:0]	rx_data,
	output			rx_data_valid);
	
	uart_tx	u_tx(
		.clk(clk),
		.rstn(rstn),
		.tx_data(tx_data),
		.tx_data_valid(tx_data_valid),
		.tx(tx),
		.tx_ready(tx_ready));
	
	uart_rx	u_rx(
		.clk(clk),
		.rstn(rstn),
		.tx_data_valid(tx_data_valid),
		.rx(rx),
		.rx_data(rx_data));	
endmodule

下面阐述tx和rx部分:

module urat_tx(
	input clk,
	input rstn,
	
	input [7:0]		tx_data,
	input			tx_data_valid,
	output			tx_ready,
	output			tx
);

	parameter CHECK_MODE = 1;//1 odd
	
	localparam IDLE		= 3'd0;
	localparam START	= 3'd1;
	localparam TDATA	= 3'd2;
	localparam CHECK	= 3'd3;
	localparam STOP		= 3'd4;

	reg [2:0] st_cur;
	reg [2:0] st_next;

//---------------------------------------------------
//data buffer
	reg [7:0]	tx_data_r;
	reg 		tx_ready_r;
	always @(posedge clk or negedge rstn)begin
		if(!rstn)begin
			tx_data_r  <= 8'hFF;
			tx_ready_r <= 1'b1;
		end
//外部给valid信号拉高,同时内部不再工作状态(ready为高),将ready拉低,同时将外部数据缓存
		else if(tx_data_valid && tx_ready)begin
			tx_data_r	<= tx_data;
			tx_ready_r	<= 1'b0;
		end
//一个传输过程结束,将ready拉高
		else if(st_cur == STOP && baud_cnt_half && st_next == IDLE)begin
			tx_ready_r	<= 1'b1;
		end
	end
	assign tx_ready = tx_ready_r;

//---------------------------------------------------
//baud counter
	parameter BAUND_NUM = 50_000_000/115200
	reg [8:0]	baud_cnt_r;
	wire		baud_cnt_end 	= (baud_cnt_r == BAUND_NUM-1);
	wire		baud_cnt_half	= (baud_cnt_r == BAUND_NUM/2 - 1);
	always @(posedge clk or negedge rstn)begin
		if(!rstn)begin
			baud_cnt_r <= 'b0;
		end
		else if(st_cur == IDLE)begin
			baud_cnt_r <= 'b0;
		end
		else begin
			if(baud_cnt_end)begin
				baud_cnt_r <= 'b0;
			end
			else begin
				baud_cnt_r <= baud_cnt_r + 1;
			end
		end
	end
//---------------------------------------------------------
//bit count
	reg [2:0] bit_cnt_r;
	always @(posedge clk or negedge rstn)begin
		if(!rstn)
			bit_cnt_r <= 'b0;
		else if(st_cur == TDATA) begin
			if(baud_cnt_end)begin
				bit_cnt_r <= bit_cnt_r + 1'b1;
			end
		end
		else begin
			bit_cnt_r <= 1'b0;
		end
	end
//----------------------------------------------------------
//Receiving FSM
	//(1) state transfer
	always @(posedge clk or negedge rstn)begin
		if(!rstn)
			st_cur <= IDLE;
		else 
			st_cur <= st_next;
	end
	
	//(2)state switch
	reg		check_mode_ok;
	always @(*)begin
		case(st_cur)
			IDLE:begin
				if(tx_data_valid && tx_ready)//start condition
					st_next = START;
				else
					st_next = IDLE;
			end
			START:begin
				if(baud_cnt_end)
					st_next = TDATA;
				else
					st_next = START;
			end
			TDATA:begin
				if(baud_cnt_end && bit_cnt_r == 7)
					st_next = CHECK;
				else
					st_next = TDATA;
			end
			CHECK:begin
				if(baud_cnt_end)begin
						st_next = STOP;
				else
						st_next = CHECK;
				end
			end
			STOP:begin
				if(baud_cnt_half)
					st_next = IDLE;
				else
					st_next = STOP;
			end
			default: st_next = IDLE;
		endcase
	end
	
	//(3) data out
	reg			tx_r;
	always @(posedge clk or negedge rstn) begin
		if(!rstn)begin
			tx_r					<= 1'b1;
		end
		else if(st_cur == IDLE && baud_cnt_r == 5)begin
			tx_r					<= 1'b1;
		end
		else if(st_cur == START && baud_cnt_r == 5)begin
			tx_r					<= 1'b0;
		end
		else if(st_cur == TDATA && baud_cnt_r == 5)begin
			tx_r					<= tx_data_r[bit_cnt_r];
		end
		else if(st_cur == CHECK && baud_cnt_r == 5)begin
			tx_r					<= ~(^tx_data_r[7:0]);//奇校验
//	tx_r					<= ^{tx_data_r,CHECK_MODE};//更为全面的写法
//	for odd check,tx_r <=~(^tx_data_r[7:0]); for even check ,(^tx_data_r[7:0])
//so tx_r	<=	^{tx_data_r[7:0],CHECK_MODE},check_mode equal 1 for odd,equal 0 for even
		end
		else if(st_cur == STOP && baud_cnt_r == 5)begin
			tx_r					<= 1'b1;
		end
	end
	assign tx		 = tx_r;
	
endmodule
module urat_rx(
	input clk,
	input rstn,
	
	input 			rx,
	output [7:0]	rx_data,
	output			rx_data_valid	 
);

	parameter CHECK_MODE = 1;//1 odd
	
	localparam IDLE		= 3'd0;
	localparam START	= 3'd1;
	localparam RDATA	= 3'd2;
	localparam CHECK	= 3'd3;
	localparam STOP		= 3'd4;

	reg [2:0] st_cur;
	reg [2:0] st_next;

//---------------------------------------------------
//rx negedge detect
//检测下降沿,表示数据传输的开始;另外进行数据打拍,这是因为可能是异步数据,打拍打了
	reg [3:0] rx_r;
	always @(posedge clk or negedge rstn)begin
		if(!rstn)
			rx_r <= 4'b1111;
		else
			rx_r <= {rx_r[2:0],rx};	
	end
	wire rx_neg = rx_r[3] & !rx_r[2];

/*打拍的写法等价于:
    else
			rx_r[0] 	<= rx;
			rx_r[1]		<= rx_r[0];
			rx_r[2]		<= rx_r[1];
			rx_r[3]		<= rx_r[2];
	end
这里是打了四拍,可以用第三拍的数据,实际可以根据情况去打。
*/

//---------------------------------------------------
//baud counter
	parameter BAUD_NUM = 50_000_000/115200
	reg [8:0]	baud_cnt_r;
	wire		baud_cnt_end 	= (baud_cnt_r == BAUD_NUM-1);
	wire		baud_cnt_half	= (baud_cnt_r == BAUD_NUM/2 - 1);
	always @(posedge clk or negedge rstn)begin
		if(!rstn)begin
			baud_cnt_r <= 'b0;
		end
		else if(st_cur == IDLE)begin
			baud_cnt_r <= 'b0;
		end
		else begin
			if(baud_cnt_end)begin
				baud_cnt_r <= 'b0;
			end
			else begin
				baud_cnt_r <= baud_cnt_r + 1;
			end
		end
	end
//---------------------------------------------------------
//bit count
	reg [2:0] bit_cnt_r;
	always @(posedge clk or negedge rstn)begin
		if(!rstn)
			bit_cnt_r <= 'b0;
		else if(st_cur == RDATA) begin
			if(baud_cnt_end)begin
				bit_cnt_r <= bit_cnt_r + 1'b1;
			end
		end
		else begin
			bit_cnt_r <= 1'b0;
		end
	end
//----------------------------------------------------------
//Receiving FSM
	//(1) state transfer
	always @(posedge clk or negedge rstn)begin
		if(!rstn)
			st_cur <= IDLE;
		else 
			st_cur <= st_next;
	end
	
	//(2)state switch
	reg		check_mode_ok;
	always @(*)begin
		case(st_cur)
			IDLE:begin
				if(rx_neg)
					st_next = START;
				else
					st_next = IDLE;
			end
			START:begin
				if(baud_cnt_end)
					st_next = RDATA;
				else
					st_next = START;
			end
			RDATA:begin
				if(baud_cnt_end && bit_cnt_r == 7)
					st_next = CHECK;
				else
					st_next = RDATA;
			end
			CHECK:begin
				if(baud_cnt_end)begin
					if(check_mode_ok)//必须再检测条件满足的条件下才会进入下个状态,否则到idle
						st_next = STOP;
					else
						st_next = IDLE;
				else
					st_next = IDLE;
				end
			end
			STOP:begin
				if(baud_cnt_half)
					st_next = IDLE;
				else
					st_next = STOP;
			end
			default: st_next = IDLE;
		endcase
	end
	
	//(3) data out
	reg	[7:0]	rx_data_r;
	reg			rx_data_valid_r;
	always @(posedge clk or negedge rstn) begin
		if(!rstn)begin
			rx_data_r		<= 0;
			rx_data_valid_r	<= 0;
		end
//RDATA状态下,每次的baund_cnt_half状态下把单bit数据放到缓存中
		else if(st_cur == RDATA && baud_cnt_half)begin
			rx_data_r[bit_cnt_r]	<=	rx_r[2]; 
		end
//CHECK状态下,如果检测满足的条件下,将valid拉高,表示往外给的数据是正确的
		else if(st_cur == CHECK && st_next == STOP && check_mode_ok)begin
			rx_data_valid_r			<=	1'b1;
		end
		else begin
			rx_data_valid_r			<=	1'b0;
		end
	end
	assign rx_data			= rx_data_r;
	assign rx_data_valid 	= rx_data_valid_r;
	
	//check logic
	always @(posedge clk or negedge rstn)begin
		if(!rstn)begin
            check_mode_ok <= 1'b1;
	    end
//奇偶校验逻辑
	    else if(st_cur == CHECK && baud_cnt_half && (^{rx_data_r,rx_r[2]} == CHECK_MODE))begin
		    check_mode_ok <= 1'b1;
	    end
	    else if(st_cur == IDLE)begin
		    check_mode_ok <= 1'b0;
	    end    
    end
endmodule

整体框架如下图:

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值