我们在做AXI_LITE外设时候,需要在大量的例子代码里面加入自己的寄存器和逻辑。不但麻烦而且很容易出错。
这里给大家推荐一个转接口的模块,将AXI接口转换成非常简单的pcore寄存器读写操作。
模块的接口定义是这样的 :
module up_axi #(
parameter AXI_ADDRESS_WIDTH = 16,
parameter ADDRESS_WIDTH = AXI_ADDRESS_WIDTH - 2
) (
// reset and clocks
input up_rstn,
input up_clk,
// axi4 interface
input up_axi_awvalid,
input [(AXI_ADDRESS_WIDTH-1):0] up_axi_awaddr,
output up_axi_awready,
input up_axi_wvalid,
input [31:0] up_axi_wdata,
input [ 3:0] up_axi_wstrb,
output up_axi_wready,
output up_axi_bvalid,
output [ 1:0] up_axi_bresp,
input up_axi_bready,
input up_axi_arvalid,
input [(AXI_ADDRESS_WIDTH-1):0] up_axi_araddr,
output up_axi_arready,
output up_axi_rvalid,
output [ 1:0] up_axi_rresp,
output [31:0] up_axi_rdata,
input up_axi_rready,
// pcore interface
output up_wreq,
output [(ADDRESS_WIDTH-1):0] up_waddr,
output [31:0] up_wdata,
input up_wack,
output up_rreq,
output [(ADDRESS_WIDTH-1):0] up_raddr,
input [31:0] up_rdata,
input up_rack
);
这里我们看到up_wreq以及之后的7个端口,就是转成了我们熟悉的寄存器读写的接口。如果熟悉wishbone总线的朋友肯定觉得很熟悉,不过wishbone是读写公用一组地址线,而这里则是分开两组。
看图说话比较明了:图中绿色部分就是axi lite部分总线,蓝色部分8跟线是转换后的。
1,首先介绍一下pcore的8根输入输出含义。
2,介绍一下valid的超时处理机制。这里等待31个周期后就自动确认防止处理器被挂起。
3,要保证读写信号只保持一次的效果,valid输出就不能使用寄存器。(如果要多个周期后才能确认valid,用户代码需要自行保证写或者读只有一次起作用)。
4,注意是字地址,每个寄存器之间的地址差是4字节。
#define BASE_ADDR 0x43c00000
#define reg(n) *(volatile unsigned int *) ( 0x43c00000 + 4 * n)
看实际的例子代码,介绍代码。
1,这里注意生成AXI LITE外设时要选择512个寄存器。使用这个转接口,不需要寄存器就不会生成,因此不会造成浪费。
2,另外注意咱们上述写的valid输出不能使用寄存器,就是不能有周期的延迟。
3,这里代码代码加完了LED显示,这样写就主要是为了验证是否进行了多次读写,我们通过看led的指示情况发现确实只执行了一次读写。
// Add user logic here
wire rstn = s00_axi_aresetn ;
wire clk = s00_axi_aclk ;
reg [31:0] reg0;
always @(posedge clk)if (rstn==0)reg0<=0;
else if (up_wreq & up_waddr==0 ) reg0 <= up_wdata + reg0 ;
else if (up_rreq & up_raddr==0 ) reg0 <= reg0 - 1;
assign up_rdata = reg0 ;
assign led = reg0[7:0] ;
assign up_wack = (up_wreq & up_waddr==0 ) ;
assign up_rack = (up_rreq & up_raddr==0 ) ;
// User logic ends
#include
#include "platform.h"
void print(char *str);
#define reg0 *(volatile unsigned int *) 0x43c00000
int main()
{
unsigned int r;
init_platform();
print("Hello World\n\r");
reg0 = 1 ;
reg0 = 1;
// led now is 2
printf("led now shuld be 2 \n" ) ;
// while(1) ;
// getchar ();
r=reg0 ;
printf("reg0 is %d \n",r) ;
// getchar ();
// led now is 1
while(1) ;
cleanup_platform();
return 0;
}
至于其他多周期相应情况,我们之后可能会展开。
通过观察LED,观察到结果和预测一致。
以上是视频教程提纲,购买我们zedboard可以获得视频教程和对应例子项目和技术支持。
sysclk.taobao.com