当前位置:网站首页>AHB2Standard_handshake_bridge 设计

AHB2Standard_handshake_bridge 设计

2022-06-11 19:27:00 Starry丶


1. 功能描述

AHB协议毕竟与FIFO、RAM等读写协议不一样,而AHB是SoC系统片内常用的高速接口,所以就需要将AHB的时序转化为标准的握手时序,此处研究AHB到标准握手的桥接器,实现接口转化。

例如下图

在这里插入图片描述

是的,AHB2HANDSHAKE桥是作为AHB slave呈现的,由此可以得出桥接器的输入输出

2. 参数描述

Group Signal Direction Width(bits) Description
AHB slavehrstninput1复位信号
hclkinput1时钟
haddrinputHADDR_WIDTH用于访问内部寄存器的地址
hburstinput3burst传输格式
hsizeinput3数据传输有效位
htransinput2传输状态
hwriteinput11表示写,0表示读
hselinput1选通
hwdatainputHDATA_WIDTH写数据
hrdataoutputHDATA_WIDTH读出的数据
hreadyoutoutput1准备标志
hrespoutput1反馈当前传输是否存在错误
Standard HandshakewaddroutputHADDR_WIDTH写地址
wdataoutputHDATA_WIDTH写数据
wr_enoutput1写使能
wreadyinput1写准备
raddroutputHADDR_WIDTH读地址
rdatainputHDATA_WIDTH读数据
rdata_valinput1读数据有效
rd_enoutput1读使能
rreadyinput1读准备

之后是参数描述

Parameter Units Description
HADDR_WIDTHbit地址位宽
HDATA_WIDTHbit写入or读出的数据位宽
ACCESS_ADDR1、ACCESS_ADDR2、ACCESS_ADDR3、ACCESS_ADDR4bit可访问地址

3. 逻辑设计

在这里插入图片描述

从上图可以看出,AHB2HANDSHAKE模块是作为AHB slave出现的,所以要从AHB Slave角度进行设计。

依然是按照状态机的思路。如果是状态机的思路,AHB协议中HTRANS有四种状态、HBURST有八种状态,我们使用哪一个呢?还是自己写状态机?

可选择思路是基于HTRANS的IDLE、BUSY、NONSEQ和SEQ四种状态进行设计,毕竟burst传输属于NONSEQ或SEQ状态。

3.1. HTRANS没法用

哈哈哈我根据HTRANS的四种状态设计了半天发现作为AHB slave压根就没法用状态机。

先看看下面这几张波形图,从AHB Slave的角度思考一下

在这里插入图片描述

在这里插入图片描述

上图中揭示了AHB比较膈应的地方,就是一次访问地址和数据是分两拍进行的,当然这也是实现流水的基础。这就导致了第二拍传数据的时候,地址可以发生变化。

所以如果对一个地址的访问需要两拍,注意这两拍中address phase与data phase可不在同一个HTRANS,data phase甚至会跨越多个HTRANS状态。

换句话说就是,HTRANS这个状态机不能决定hwdata和hrdata信号的变化规律。
这个与平时的状态机设计不同,平时设计的思路是整个模块被分成好几个状态,该模块的每个信号会根据不同状态变化规律不一。
但是AHB协议中HADDR会根据HTRANS的取值来决定是否有效,而HWDATA和HRDATA的变化并不会参照HTRANS这个状态。

但是作为AHB Slave不必关心有没有跨HTRANS、HTRANS某个状态是否要延迟,这个是AHB Master要做的事情。作为slave,只需要将数据正确写入或正确读出即可

那么如何对AHB到标准握手时序桥进行设计呢?还是状态机,不过我们采用最原始的状态机:

在这里插入图片描述

3.2. IDLE

该状态下当然是啥都不干啦,当检测到AHB master要进行传输时,即htrans为NONSEQ时,检测hwrite判断转入WRITE还是READ,如下图

在这里插入图片描述

于是状态机重写为

在这里插入图片描述

3.3. 写

该状态下实现写,当标准握手时序下写完成该状态结束。

注意是标准握手时序,所以需要将地址和数据在时序上对齐。

怎么实现呢?时序图在IDLE已经展现了,如下图带反压的WRITE

在这里插入图片描述

即便是burst写也可以

在这里插入图片描述

而WRITE下一个状态,则根据WRITE结束的那一拍htrans的值,状态机如下

在这里插入图片描述

关于那个BUSY作一下说明。AHB master在进入BUSY时会给出下一个传输的控制信号,但是在下一次传输真正来临时控制信号还会保持不变,所以在AHB slave检测到wr_en && hready && (htrans == BUSY)时依旧可以转换为IDLE状态

3.4. 读

该状态下实现读,当确定读出数据了该状态结束。

同样要求rd_en与rdata时序对齐,如果与写类似,将haddr打拍成raddr,那么在data phase第一拍必然不会读出数据,最快也要第二拍。

也就是说,必然会反压一拍,如下图带延迟的情况。

在这里插入图片描述

由此状态机更新为

在这里插入图片描述

3.5. 代码

module ahb2standard_handshake_bridge#(
	parameter	HADDR_WIDTH = 32,
	parameter	HDATA_WIDTH = 32
	parameter	ACCESS_ADDR1 = 32'h0000_0000_0000_0010,
	parameter	ACCESS_ADDR2 = 32'h0000_0000_0000_0014,
	parameter	ACCESS_ADDR3 = 32'h0000_0000_0000_0018,
	parameter	ACCESS_ADDR4 = 32'h0000_0000_0000_001C
	)(
	input 						hrstn,
	input 						hclk,
	input	[HADDR_WIDTH-1:0]	haddr,
	input	[2:0]				hburst,
	input	[2:0]				hsize,
	input	[1:0]				htrans,
	input						hwrite,
	input						hsel,
	input	[HDATA_WIDTH-1:0]	hwdata,
	output	[HDATA_WIDTH-1:0]	hrdata,
	output						hready,
	output						hresp,
	
	output	[HADDR_WIDTH-1:0]	waddr,
	output	[HDATA_WIDTH-1:0]	wdata,
	output						wr_en,
	input						wready,
	
	output	[HADDR_WIDTH-1:0]	raddr,
	input	[HDATA_WIDTH-1:0]	rdata,
	input						rdata_val,
	output						rd_en,
	input						rready
	);

localparam		IDLE = 2'b00;
localparam		WRITE = 2'b01;
localparam		READ = 2'b11;

reg		[1:0]				cur_state;
reg		[1:0]				nxt_state;
reg		[HADDR_WIDTH-1:0]	waddr_r;
reg		[HADDR_WIDTH-1:0]	raddr_r;
reg							hready_r;
reg							wr_en_r;
reg							rd_en_r;
reg							hresp_r;

[email protected](posedge hclk or negedge hrstn) begin
	if(!hrstn)
		cur_state <= IDLE;
	else
		cur_state <= nxt_state;
end

[email protected](*) begin
	case(cur_state)
		IDLE:
			if(htrans[1]) begin
				if(hwrite)
					nxt_state = WRITE;
				else
					nxt_state = READ;
			end
			else
				nxt_state = IDLE;
		WRITE:
			if(wr_en && hready) begin
				if(!htrans[1])
					nxt_state = IDLE;
				else if(!hwrite)
					nxt_state = READ;
				else
					nxt_state = WRITE;
			end
			else
				nxt_state = WRITE;
		READ:
			if(rdata_val) begin
				if(!htrans[1])
					nxt_state = IDLE;
				else if(hwrite)
					nxt_state = WRITE;
				else
					nxt_state = READ;
			end
			else
				nxt_state = READ;
		default:
			nxt_state = IDLE;
	endcase
end


assign wdata = hwdata[(8 << hsize)-1:0];

[email protected](*) begin
	case(cur_state)
		IDLE:
			hready_r = 1'b0;
		WRITE:
			hready_r = wready;
		READ:
			hready_r = rdata_val;
		default:
			hready_r = 1'b0;
	endcase
end

assign hready = hready_r;

[email protected](posedge hclk or negedge hrstn) begin
	if(!hrstn)
		waddr_r <= 'd0;
	else if(cur_state == IDLE) begin
			if(htrans[1] && hwrite)
				waddr_r <= haddr;
		end
	else if(cur_state == WRITE) begin
			if(wr_en && hready && htrans[1] && hwrite)
				waddr_r <= haddr;
		end
	else if(cur_state == READ) begin
			if(rdata_val && htrans[1] && hwrite)
				waddr_r <= haddr;
		end
end

assign waddr = waddr_r;

[email protected](posedge hclk or negedge hrstn) begin
	if(!hrstn)
		wr_en_r <= 1'b0;
	else if(cur_state == IDLE) begin
			if(htrans[1] && hwrite)
				wr_en_r <= 1'b1;
		end
	else if(cur_state == WRITE) begin
			if(!hready)
				wr_en_r <= wr_en_r;
			else if(htrans[1]) begin
					if(hwrite)
						wr_en_r <= 1'b1;
					else
						wr_en_r <= 1'b0;
				end
			else
				wr_en_r <= 1'b0;
		end
	else if(cur_state == READ) begin
			if(rdata_val && htrans[1] && hwrite)
				wr_en_r <= 1'b1;
		end
end

assign wr_en = wr_en_r;

assign hrdata = rdata[(8 << hsize)-1:0];

[email protected](posedge hclk or negedge hrstn) begin
	if(!hrstn)
		raddr_r <= 'd0;
	else if(cur_state == IDLE) begin
			if(htrans[1] && !hwrite)
				raddr_r <= haddr;
		end
	else if(cur_state == WRITE) begin
			if(wr_en && hready && htrans[1] && !hwrite)
				raddr_r <= haddr;
		end
	else if(cur_state == READ) begin
			if(rdata_val && htrans[1] && !hwrite)
				raddr_r <= haddr;
		end
end

assign raddr = raddr_r;

[email protected](posedge hclk or negedge hrstn) begin
	if(!hrstn)
		rd_en_r <= 1'b0;
	else if(cur_state == IDLE) begin
			if(htrans[1] && !hwrite)
				rd_en_r <= 1'b1;
		end
	else if(cur_state == WRITE) begin
			if(wr_en && hready && htrans[1] && !hwrite)
				rd_en_r <= 1'b1;
		end
	else if(cur_state == READ) begin
			if(!rready)
				rd_en_r <= rd_en_r;
			else if(!rdata_val)
				rd_en_r <= 1'b0;
			else if(htrans[1]) begin
					if(hwrite)
						rd_en_r <= 1'b0;
					else
						rd_en_r <= 1'b1;
				end
			else
				rd_en_r <= 1'b0;
		end
	else 
		rd_en_r <= 1'b0;
end

assign rd_en = rd_en_r;

[email protected](*) begin
	if(cur_state == WRITE && wr_en && hready) begin
		if(waddr != ACCESS_ADDR1 
			&& waddr != ACCESS_ADDR2
			&& waddr != ACCESS_ADDR3
			&& waddr != ACCESS_ADDR4)
			hresp_r = 1'b1;
		end
	else if(cur_state == READ && rdata_val) begin
			if(raddr != ACCESS_ADDR1 
				&& raddr != ACCESS_ADDR2
				&& raddr != ACCESS_ADDR3
				&& raddr != ACCESS_ADDR4)
				hresp_r = 1'b1;
		end
	else
		hresp_r = 1'b0;
end

assign hresp = hresp_r;

endmodule
原网站

版权声明
本文为[Starry丶]所创,转载请带上原文链接,感谢
https://blog.csdn.net/Starry__/article/details/125229690