Wishbone总线

1. 点对点连接方式的接口说明

1
在点对点连接方式方式中,分别只有一个主设备和一个从设备。
所有信号都是高电平有效。

  • CLK_I:时钟信号,由外部输入
  • RST_I:复位信号,由外部输入
  • DAT_O / DAT_O:数据总线,一对主从设备间最多存在两条数据总线
  • ADR_O / ADR_O:地址总线,地址由主设备传送给从设备
  • WE_O / WE_O:写使能信号,代表主设备对从设备当前进行的操作,1为写,0为读
  • SEL_O / SEL_O:数据总线选择信号,也是字节选择信号,以Byte为单位,SEL(4’b 1001)代表最高和最低字节有效
  • CYC_O / CYC_O:总线周期信号,CYC有效代表一个主设备请求总线使用权或正在使用总线,但不一定正在进行总线操作(是否正在进行总线操作取决于选通信号STB是否有效)。只有在CYC信号有效的前提下,wishbone主从设备之间的其他信号才有意义。CYC信号在一次总线操作过程中必须持续有效。若一次读写操作可能需要多要时钟周期,那么CYC信号得在多个时钟周期内持续有效
  • STB_O / STB_O:选通信号,选通信号有效代表主设备发起一次总线操作
  • ACK_O / ACK_O:主从设备间的操作成功结束信号
  • TANG_O / TANG_O:标签信号,用户可以利用标签信号传递自定义信息

2. 单次读操作

在这里插入图片描述

  • 在时钟上升沿0,主设备将地址信号ADR_O、SEL_O放到总线上,将WE_O置0代表读操作,STB_O、CYC_O置高表示一次总线操作开始
  • 在时钟上升沿1到来之前,从设备检测主设备发起的操作,将数据放到主设备的输入接口DAT_I,同时将主设备ACK_I置高,作为对主设备STB_O的响应。从设备可以在设置ACK_I有效之前,插入任意数量的等待操作
  • 在时钟上升沿1,主设备发现ACK_I为高,采样DAT_I信号作为读取到的数据,并将CYC_O和STB_O置低,表示操作完成,从设备检测到STB_O为低,将主设备的ACK_I置低,单次读操作完成

3. 单次写操作

在这里插入图片描述

  • 在时钟上升沿0,主设备将地址信号ADR_O、DAT_O、SEL_O放到总线上,将WE_O置0代表写操作,STB_O、CYC_O置高表示一次总线操作开始
  • 在时钟上升沿1到来之前,从设备检测主设备发起的操作,锁存DAT_O的数据,同时将主设备的输入ACK_I置高,作为对从设备STB_O的响应。从设备可以在设置ACK_I有效之前,插入任意数量的等待操作
  • 在时钟上升沿1,主设备发现ACK_I为高,将CYC_O和STB_O置低,表示操作完成,从设备检测到STB_O为低,将主设备的ACK_I置低,单次写操作完成

4. 补充

4.1. SEL字节选择信号的说明

  • 类比加载/存储指令的字节选择信号
    OpenMIPS数据总线、地址总线都是32bit,是大端模式,使用4个8位存储器代替一个32位存储器。
    读操作时,从4个8位存储器各读取一个字节,组合位32位的数据输出;写操作时,依据sel的值,修改其中特定存储器对应的字节。32位地址的最低两位不需要使用。
    例如,SW指令是读取地址n处的字,实际就是从4个8位存储器的地址n/4处各读取一个字节,组合起来就是地址n处的字。
    在这里插入图片描述

  • 通过wishbone进行读操作时,主设备通过ADR_O送出32位地址,从设备将ADR_O最低两位置0,作为目标地址,即字节对齐后的首地址,给出对应的32位数据,输入到主设备的DAT_I。

lb $1, 0x6($0)		# 字节加载指令,加载[0x6]处的字节并作符号扩展,$1 = 0x0000 0056

OpenMIPS指令集下,该条指令对应的32位指令码为“80010006

  • 在EX模块,mem_addr = reg1 + { {16{inst_i[15]}}, inst_i[15:0] },即0x0000_0006
  • 在MEM模块,分析mem_addr[1:0]为2’b10,所以mem_sel_o <= 4’b0010,正好对应数据存储器中的data_mem1,
    wdata_o <= { {24{mem_data_i[15]}}, mem_data_i[15:8] },正好是[0x6]地址对应字节的符号扩展
    在这里插入图片描述

4.2. wishbone_bus总线接口的实现

采用状态机实现总线接口模块
在这里插入图片描述
模块端口
在这里插入图片描述

`define	WB_IDLE					2'b00
`define	WB_BUSY					2'b01
`define	WB_WAIT_FOR_STALL		2'b11
`include "defines.v"

module	wishbone_bus_if (
	input	wire					clk,
	input	wire					rst,
	
	// 来自CTRL模块
	input	wire					stall_i,			// 流水线暂停信号
	input	wire					flush_i,			// 流水线清除信号
	
	// CPU侧的接口
	input 	wire					cpu_ce_i,			// 来自处理器的访问请求信号
	input	wire	[`RegBus]		cpu_data_i,			// 来自处理器的数据
	input	wire	[`RegBus]		cpu_addr_i,			// 来自处理器的地址信号
	input	wire					cpu_we_i,			// 来自处理器的写操作信号
	input	wire	[3:0]			cpu_sel_i,			// 来自处理器的字节选择信号
	output	reg		[`RegBus]		cpu_data_o,			// 输出到处理器的数据
	
	// Wishbone侧的接口
	input	wire	[`RegBus]		wishbone_data_i,	// wishbone总线输入的数据
	input	wire					wishbone_ack_i,		// wishbone总线的响应信号
	output	reg		[`RegBus]		wishbone_addr_o,	// wishbone总线输出的地址
	output	reg		[`RegBus]		wishbone_data_o,	// wishbone总线输出的数据
	output	reg						wishbone_we_o,		// wishbone总线写使能信号
	output	reg		[3:0]			wishbone_sel_o,		// wishbone总线字节选择信号
	output	reg						wishbone_stb_o,		// wishbone总线的选通信号
	output	reg						wishbone_cyc_o,		// wishbone总线周期信号
	
	output	reg						stallreq			// 请求流水线暂停信号
);
 	
 	reg	[1:0]				wishbone_state;		// 保存wishbone总线接口模块的状态
 	reg	[`RegBus]			rd_buf;				// 寄存通过wishbone总线访问到的数据
 	
// *********************************************************************************************
// ******************** 第一阶段:控制状态转化的时序电路 ***************************************
// *********************************************************************************************
	always @ (posedge clk)	begin
		if (rst == `RstEnable)	begin
			wishbone_state	<=	`WB_IDLE;					// 状态复位
			wishbone_addr_o	<=	`ZeroWord;
			wishbone_data_o	<=	`ZeroWord;
			wishbone_we_o	<=	`WriteDisable;
			wishbone_sel_o	<=	4'b0000;
			wishbone_stb_o	<=	1'b0;
			wishbone_cyc_o	<=	1'b0;
			rd_buf					<=	`ZeroWord;
		end else	begin
			case (wishbone_state)
				`WB_IDLE:						begin
					// 处理器发出访问请求,流水线不处于清除状态,总线状态进入BUSY,开始访问总线
					if ( (cpu_ce_i == 1'b1) && (flush_i == `False_v) )	begin
						wishbone_stb_o	<=	1'b1;
						wishbone_cyc_o	<=	1'b1;
						wishbone_addr_o	<=	cpu_addr_i;
						wishbone_data_o	<=	cpu_data_i;
						wishbone_we_o	<=	cpu_we_i;
						wishbone_sel_o	<=	cpu_sel_i;
						wishbone_state	<=	`WB_BUSY;
						rd_buf			<=	`ZeroWord;
					end
				end
				`WB_BUSY:						begin
					// 收到总线的响应信号
					if (wishbone_ack_i == 1'b1)	begin
						wishbone_stb_o	<=	1'b0;									// 主从设备间的操作结束信号
						wishbone_cyc_o	<=	1'b0;
						wishbone_addr_o	<=	`ZeroWord;
						wishbone_data_o	<=	`ZeroWord;
						wishbone_we_o	<=	`WriteDisable;
						wishbone_sel_o	<=	4'b0000;
						wishbone_state	<=	`WB_IDLE;
						if (cpu_we_i	==	`WriteDisable)	begin		// 读使能有效
							rd_buf		<=	wishbone_data_i;
						end
						if (flush_i	!=	6'b000000)	begin
							// 暂停流水线,进入WB_WAIT_FOR_STALL
							wishbone_state	<=	`WB_WAIT_FOR_STALL;
						end 
					end else if (flush_i == `True_v)	begin
						// 发生异常,清除流水线,并撤销此次总线访问
						wishbone_stb_o	<=	1'b0;
						wishbone_cyc_o	<=	1'b0;
						wishbone_addr_o	<=	`ZeroWord;
						wishbone_data_o	<=	`ZeroWord;
						wishbone_we_o	<=	`WriteDisable;
						wishbone_sel_o	<=	4'b0000;
						wishbone_state	<=	`WB_IDLE;
						rd_buf			<=	`ZeroWord;
					end
				end
				`WB_WAIT_FOR_STALL:	begin
					if (stall_i == 6'b000000)	begin
						// 流水线暂停取消
						wishbone_state	<=	`WB_IDLE;
					end
				end
				default:	begin
				end
			endcase
		end
	end
	
// *********************************************************************************************
// ******************** 第二阶段:给处理器接口信号赋值的组合电路 *******************************
// *********************************************************************************************	
	always @ (*)	begin
		if (rst == `RstEnable)	begin
			stallreq		<=	`NoStop;
			cpu_data_o	<=	`ZeroWord;
		end else	begin
			stallreq		<=	`NoStop;
			case (wishbone_state)
				`WB_IDLE:		begin
					if ( (cpu_ce_i == 1'b1) && (flush_i == `False_v) )	begin
						stallreq	<=	`Stop;		// 流水线开启暂停
						cpu_data_o	<=	`ZeroWord;	// 初始状态读数据为0
					end
				end
				`WB_BUSY:		begin
					if (wishbone_ack_i == 1'b1)	begin			// 收到总线响应信号ack
						stallreq		<=	`NoStop;		// 流水线结束暂停
						if(wishbone_we_o == `WriteDisable)	begin	// 读使能
							cpu_data_o	<=	wishbone_data_i;
						end else	begin
							cpu_data_o	<=	`ZeroWord;
						end
					end else	begin							// 没有收到总线相应信号ack
						stallreq	<=	`Stop;			// 流水线保持暂停
						cpu_data_o	<=	`ZeroWord;
					end
				end
				`WB_WAIT_FOR_STALL:		begin
					stallreq	<=	`NoStop;
					cpu_data_o	<=	rd_buf;
				end
				default:	begin
				end
			endcase
		end
	end
	
endmodule
  • 4
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值