AMBA总线(二) AHB总线

◇◆丶佛笑我妖孽 提交于 2019-12-22 04:37:32

(一)AHB 总线的架构
总线周期:就是总线时钟的频率,对于AMBA AHB 或者APB 协议总线周期定义为从一个上升沿到临界的上升沿的变化区间。
总线传输:AHB 总线传输是数据目标的读写操作,可能会持续一个或者多个总线周期,而总线的传输在收到从机的ready信号终止,总线位宽为8、16、32、64、128bits。
猝发传输:定义了一个或多个数据传输,由主线总机发起,在地址空间增加时,每次传输增加的步长,由总线传输的大小决定。
在这里插入图片描述
(二)AHB总线特点

  • 高速总线,高性能
  • 流水线操作
  • 支持多个总线主设备(最多16个)
  • 支持single、burst传输
  • 总线位宽8、16、32、64、128bits
  • 上升沿触发

(三)AHB总线结构
在这里插入图片描述
(1)AHB主设备(master)

  • 初始化一次读/写操作
  • 某一时刻只允许一个主设备使用总线
  • uP、DMA、DSP、LCDC
    (2)AHB从设备(slave)
  • 响应一次读/写操作
  • 外部存储器控制器EMI、APB bridge
    (3)AHB仲裁器(arbiter)
    允许某一个主设备控制总线(没有定义仲裁算法)
    (4)AHB译码器
    通过地址译码来决定选择哪一个从设备

(四)AHB总线信号
在这里插入图片描述

  • HCLK/HRESETn(时钟与复位信号)
  • HSEL(指明当前被访问的从设备,来自译码器)
  • HADDR[31:0] (32位系统地址总线)
  • HWDATA[31:0] (写数据总线,从主设备写到从设备)
  • HRDATA[31:0] (读数据总线,从从设备读到主设备)
  • HTRANS (传输的状态有:NONSEQ、SEQ、IDLE、BUSY)
  • HSIZE(传输的数据宽度 8 、16 、32)
  • HBURST(传输的burst类型,single,incr4/8/16,wrap4/8/16)
  • HRESP(从设备发给主设备的总线传输状态:OKAY、ERROR、RETRY、SPLIT)
  • HREADY(高-从设备传输结束;低-从设备需延迟传输周期)

(五)AHB基本传输
1、地址周期(地址与控制信号),只有一个cycle
2、数据周期(读周期/写周期),由HREADY信号决定需要几个cycle
(1)没有等待的single transfer
在这里插入图片描述
第一个周期的上升沿,主机将地址信息和控制信息发送到总线上
第二个周期的上升沿,从机采样地址和控制信号,并将HREADY拉高;如果是写操作,主机会在第二个周期的上升沿后写入数据;如果是读操作,从机会在HREADY信号拉高后将读取的数据写入总线。
第三个周期的上升沿,主机获取HREADY高信号,如果是写操作,表明从机已经接收数据;如果是读操作,表明读数据有效并接收。(HREADY在数据有效器件必须为高,并且保存至第三个周期的上升沿之后)

(2)两个等待周期的single transfer
在这里插入图片描述
从机有时候存在太慢不能不处理的情况,需要插入等待状态,HREADY信号早第二和第三周期拉低,需要主机等待两个周期。如果是写操作,主机需要在等待期间保持写数据不变,直到本次传输完成;如果是读操作,从机只需在READY信号拉高后,给出数据即可。

(3)流水线AHB传输
在这里插入图片描述
由于pipeline操作,尽管进行B的读写操作时,插入了一个等待状态,但是传递三个数据总共用了5个周期。
由于AHB只能将Address 与 Data 分开,所以在AHB 中流水线的深度是2,即总线上最多存在两个未处理完成的transfer。

(4)burst传输
在这里插入图片描述
突发信息通过使用 HBURST[2:0]并且 8 种可能的类型在中定义如下:
(1)single transfer
(2)INCR 4-beat/8-beat/16-beat
(3)WRAP 4-beat/8-beat/16-beat
对于增量猝发,每一次传输地址都是前一次地址的增量
对于回环(wrap)猝发,如果传输的起始地址并未和字节总数对齐,那么传输地址将在边界处回环。例如,一个4拍回环猝发的字(4字节)访问将在16字节边界回环。因此地址将在16字节处回环,如果起始地址为0x34,即0x3c之后的地址为0x30,那么地址传输为0x34、0x38、0x3c、0x30;对于wrap8而言,地址将在32字节边界处回环,因此0x3c之后的地址如果起始地址为0x34,地址0x3c之后的地址是0x20,那么地址传输为0x34,0x38、0x3c、0x20、0x24、0x28、0x2c、0x30.
注意:
burst传输不能穿越KB边界,比如由0x000传输至0x400时,穿越KB边界必须将猝发模式由SEQ转为NSEQ,并继续传输。这是由于slave的地址一般以KB分界,避免数据传输时发生错误

在这里插入图片描述
在这里插入图片描述
HTRANS[1:0] :
00:IDLE(主设备占用总线,但没有进行传输;两次burst传输中间主设备发送IDLE)
01:BUSY(主设备占用总线,但是在burst传输过程中还没有准备好进行下一次传输;一次burst传输中间主设备发BUSY)
10:NONSEQ (表明一个单个数据的传输或者一个burst传输的第一个数据;其地址与控制信号与上一次传输无关)
11:SEQ(表明burst传输接下来的数据;地址与上一次传输的地址是相关的)
在这里插入图片描述
其他控制信号:
HWRITE:高电平:写;低电平:读
HSIZE[2:0]:
000:8bits
001:16bits
010:32bits
011:64bits
100:128bits
101:256bits
110:512bits
111:1024bits
在这里插入图片描述
注意:猝发大小表示猝发的节拍数量,并不是一次猝发传输的实际字节数量。一次猝发数据总量可以用节拍数乘以每拍数据的字节数来计算,每拍字节数由HSIZE[2:0]确定,并且猝发传输必须将地址边界与传输大小对齐。
由于猝发传输的大小受限->
下面是一个软件(汇编)与硬件对应的图:
在这里插入图片描述
HRESP[1:0] 的编码、传输响应信号和每个响应的描述如下:
在这里插入图片描述
(五)仲裁信号
在这里插入图片描述

  • HBUSREQ(总线请求 ,master发出)
  • HLOCKx(高电平:主设备请求锁定总线,master发出)
  • HGRANTx(指出主设备x可访问总线,arbiter 发出;主设备x控制总线,当HGRANTx=1且HREADY=1)
  • HMASTER[3:0](正在传输的主设备)
  • HMASTLOCK(主设备正在进行一次锁定传输)
  • HSPLITx[15:0](从设备用这个信号告诉仲裁器哪个主设备允许重新尝试一次split传输)

(1)无等待仲裁
在这里插入图片描述
(2)有等待仲裁
在这里插入图片描述
AHB主设备端口
在这里插入图片描述
AHB从设备端口
在这里插入图片描述
下面是AHB slave的RTL代码:

module ahb_slave(
	input hclk,
	input hreset_n,
	input hselx,
	input [31:0] haddr,
	input hwrite,
	input [1:0] htrans,
	input [2:0] hsize,
	input [2:0] hburst,
	input [31:0] hwdata,
	output reg hready,
	output [1:0] hresp,
	output reg [31:0] hrdata);
reg hready1;
reg hready2;
reg hready3;
reg hready4;

wire [7:0] addr1= haddr[7:0];

reg [7:0] hrdata1;
reg [7:0] hrdata2;
reg [7:0] hrdata3;
reg [7:0] hrdata4;


parameter bits8 = 3'b000;
parameter bits16 = 3'b001;
parameter bits32 = 3'b010;
parameter bits64 = 3'b011;
parameter bits128 = 3'b100;
parameter bits256 = 3'b101;
parameter bits512 = 3'b110;
parameter bits1024 = 3'b111;

parameter single=3'b000;
parameter incr=3'b001;
parameter wrap4=3'b010;
parameter incr4=3'b011;
parameter wrap8=3'b100;
parameter incr8=3'b101;
parameter wrap16=3'b110;
parameter incr16=3'b111;

parameter okay=2'b00;
parameter error=2'b01;
parameter retry=2'b10;
parameter split=2'b11;

reg [31:0] data [256-1:0];
integer i;
//read and write


always@(posedge hclk or negedge hreset_n)
begin
	if(!hreset_n)
	begin
		for(i=0;i<=256-1;i=i+1)
		begin
			data[i]<=0;
		end
		hready<=1'b0;
		hrdata<=32'b0;
		hrdata1<=8'h0;
		hrdata2<=8'h0;
		hrdata3<=8'h0;
		hrdata4<=8'h0;
	end
	else 
	begin
		case(hburst)
		single:
		begin
			if(!hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1'b1;
				hready1<=hready;
				if(hready1==1)
				begin
					hrdata<={hrdata4,hrdata3,hrdata2,hrdata1};
					case(hsize)
					bits8:
					begin
						hrdata1<=data[addr1];
					end
					bits16:
					begin
						hrdata1<=data[addr1];
						hrdata2<=data[addr1+1];
							
					end
					bits32:
					begin
						hrdata1<=data[addr1];
						hrdata2<=data[addr1+1];
						hrdata3<=data[addr1+2];
						hrdata4<=data[addr1+3];
					end
					endcase
				end
			end
			else if(hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1'b1;
				hready1<=hready;
				if(hready1==1)
				begin
					case(hsize)
					bits8:
					begin
						data[addr1]<=hwdata[7:0];
					end
					bits16:
					begin
						data[addr1]<=hwdata[7:0];
						data[addr1+1]<=hwdata[15:8];
					end
					bits32:
					begin
						data[addr1]<=hwdata[7:0];
						data[addr1+1]<=hwdata[15:8];
						data[addr1+2]<=hwdata[23:16];
						data[addr1+3]<=hwdata[31:24];
					end
					endcase
				end
			end
		end
		incr4:
		begin
			if(!hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1;
				hready1<=hready;
				hready2<=hready1;
				hready3<=hready2;
				hready4<=hready3;
				case(hsize)
					bits32:
					begin
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1+4];
						else if(hready3==1)
							hrdata<=data[addr1+8];
						else if(hready4==1)
							hrdata<=data[addr1+12];
					end
				endcase
			end
			else if(hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1;
				hready1<=hready;
				hready2<=hready1;
				hready3<=hready2;
				hready4<=hready3;
				case(hsize)
					bits32:
					begin
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1+4]<=hwdata;
						else if(hready3==1)
							data[addr1+8]<=hwdata;
						else if(hready4==1)
							data[addr1+12]<=hwdata;
					end
				endcase
			end
		end
		wrap4:
		begin
			if(!hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1;
				hready1<=hready;
				hready2<=hready1;
				hready3<=hready2;
				hready4<=hready3;
				case(hsize)
				bits32:
				begin
					if(hready1==1)
					begin
					case(addr1[3:0])
					4'h0:
						begin
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1+4];
						else if(hready3==1)
							hrdata<=data[addr1+8];
						else if(hready4==1)
							hrdata<=data[addr1+12];
						end
					4'h4:
						begin
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1+4];
						else if(hready3==1)
							hrdata<=data[addr1+8];
						else if(hready4==1)
							hrdata<=data[addr1-4];
						end
					4'h8:
						begin					
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1+4];
						else if(hready3==1)
							hrdata<=data[addr1-8];
						else if(hready4==1)
							hrdata<=data[addr1-4];
						end
					4'hc:
						begin
						if(hready1==1)
							hrdata<=data[addr1];
						else if(hready2==1)
							hrdata<=data[addr1-12];
						else if(hready3==1)
							hrdata<=data[addr1-8];
						else if(hready4==1)
							hrdata<=data[addr1-4];
						end
					endcase
					end
				end
				endcase
			end
			else if(hwrite&&hselx&&(htrans[1:0]==2'b10))
			begin
				hready<=1;
				hready1<=hready;
				hready2<=hready1;
				hready3<=hready2;
				hready4<=hready3;
				case(hsize)
				bits32:
				begin
					if(hready1==1)
					begin
					case(addr1[3:0])
					4'h0:
						begin
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1+4]<=hwdata;
						else if(hready3==1)
							data[addr1+8]<=hwdata;
						else if(hready4==1)
							data[addr1+12]<=hwdata;
						end
					4'h4:
						begin
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1+4]<=hwdata;
						else if(hready3==1)
							data[addr1+8]<=hwdata;
						else if(hready4==1)
							data[addr1-4]<=hwdata;
						end
					4'h8:
						begin					
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1+4]<=hwdata;
						else if(hready3==1)
							data[addr1-8]<=hwdata;
						else if(hready4==1)
							data[addr1-4]<=hwdata;
						end
					4'hc:
						begin
						if(hready1==1)
							data[addr1]<=hwdata;
						else if(hready2==1)
							data[addr1-12]<=hwdata;
						else if(hready3==1)
							data[addr1-8]<=hwdata;
						else if(hready4==1)
							data[addr1-4]<=hwdata;
						end
					endcase
					end
				end
				endcase	
			end
		end
		endcase
	end
end
endmodule										
module tb();
reg hclk;
reg hreset_n;
reg hselx;
reg [31:0] haddr;
reg hwrite;
reg [1:0] htrans;
reg [2:0] hsize;
reg [2:0] hburst;
reg [31:0] hwdata;
wire hready;
wire [31:0] hrdata;

ahb_slave u1(
	.hclk(hclk),
	.hreset_n(hreset_n),
	.hselx(hselx),
	.haddr(haddr),
	.hwrite(hwrite),
	.htrans(htrans),
	.hsize(hsize),
	.hburst(hburst),
	.hwdata(hwdata),
	.hready(hready),
	.hresp(),
	.hrdata(hrdata));
initial
begin
	hclk=0;
	forever #(20/2) hclk=~hclk;
end

initial
begin
	hreset_n=0;
	#(60) hreset_n=1;
	hwrite=1;
	hselx=1;
	haddr=32'h45684120;
	hsize=3'b010;
	hburst=3'b000;
	htrans=2'b10;
	#(20);
	hwdata=32'h123045;
	#(40);
	hwrite=1;
	hselx=1;
	haddr=32'h45684124;
	hsize=3'b010;
	hburst=3'b010;
	htrans=2'b10;
	#(20);
	hwdata=32'h546123;
	#(20);
	hwdata=32'h123456;
	#(20);
	hwdata=32'h11111111;
	#(20);
	hwdata=32'h22222222;
	#(100);
	hwrite=0;
	hselx=1;
	haddr=32'h45684120;
	hsize=3'b010;
	hburst=3'b000;
	htrans=2'b10;
	#(40);
	hwrite=0;
	hselx=1;
	haddr=32'h45684124;
	hsize=3'b010;
	hburst=3'b010;
	htrans=2'b10;
end
endmodule

在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!