Nios II嵌入式系统驱动设计(三)
在SOPC中自定义元件的端口设置解析 中讲述了各种Avalon自定义接口的端口设置,在SOPC自定义元件的添加及运行中介绍了如何将已编写好代码的元件集成到SOPC Builder中,在本文中将介绍如何编写能够挂载到Avalon上的Slave接口的端口代码编写方法。
Slave interface(接口)代码编写:
Slave interface包含如下端口:
Signal Type | Direction | v7.1 and Earlier Interface | v7.2 and Later Interface |
---|---|---|---|
clk | Input | Global | Clock Input (1) |
reset | Input | Global | Clock Input (1) |
address | Input | Avalon Slave | Avalon Slave |
read | Input | Avalon Slave | Avalon Slave |
readdata | Output | Avalon Slave | Avalon Slave |
write | Input | Avalon Slave | Avalon Slave |
writedata | Input | Avalon Slave | Avalon Slave |
waitrequest | Output | Avalon Slave | Avalon Slave |
irq | Output | Avalon Slave | Interrupt Sender |
my_export_signals | Input, Output, or Bidir | Global | Conduit |
在8.0版本中,Slave接口中去掉了chipselect端口,也增加了上面表格中没有的byteenable端口,slave inteface代码编写实例如下:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
module slave (
// these connect to the clock port
clk,
reset,
// these connect to the slave port
slave_address,
slave_read,
slave_readdata,
slave_write,
slave_writedata,
slave_byteenable,
// this connects to the irq sender port
control_irq
// Conduit port
Out<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />2In,
In2Out,
);
input clk;
input reset;
input [2:0] slave_address;
input slave_read;
output wire [31:0] slave_readdata;
input slave_write;
input [31:0] slave_writedata;
input [3:0] slave_byteenable;
output control_irq;
input Out2In;
output In2Out;
/****************************************************************************/
// definition register in Slave
reg [31:0] status_register;
reg [31:0] read_address_register;
reg [31:0] length_register;
reg [31:0] control_register;
wire [31:0] control_readdata_temp;
reg [31:0] control_readdata_temp_d1;
wire [31:0] checksum_register;
/****************************************************************************/
//write length register
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
length_register <= 0;
end
else
begin
if ((slave_address == 3'b011) & (slave_write == 1))//assert to write length register
begin
if (slave_byteenable[0] == 1)
begin
length_register[7:0] <= slave_writedata[7:0];
end
if (slave_byteenable[1] == 1)
begin
length_register[15:8] <= slave_writedata[15:8];
end
if (slave_byteenable[2] == 1)
begin
length_register[23:16] <= slave_writedata[23:16];
end
if (slave_byteenable[3] == 1)
begin
length_register[31:24] <= slave_writedata[31:24];
end
end
end
end
//you can write other register like this.
/**********************************************************************/
//read register
assign control_readdata_temp = (slave_address == 3'b000)? status_register :
(slave_address == 3'b001)? read_address_register :
(slave_address == 3'b011)? length_register :
(slave_address == 3'b110)? control_register :
(slave_address == 3'b111)? checksum_register : 0;
always @ (posedge clk or posedge reset)
begin
if (reset)
begin
control_readdata_temp_d1 <= 0;
end
else
begin
if (slave_read == 1)//assert to read register
begin
control_readdata_temp_d1 <= control_readdata_temp;//the content is according to the slave_address
end
end
end
assign slave_readdata = control_readdata_temp_d1;//assign the register data to the slave_readdata.
/*****************************************************************************/
//interrupt sender
assign control_irq = status_register[0] & control_register[4];
/*****************************************************************************/
//do some algorithm, receive Out2In from outside SOPC system, export In2Out to outside SOPC system
XXX <= Out2In;
………………….
In2Out <= YYY;
/*****************************************************************************/
在register map文件 component_reg.h文件中定义了这些寄存器的地址,以便驱动文件读写这些寄存器。
下面为status寄存器的地址映射代码,其他寄存器也类似,只是偏移地址根据程序中设定的地址具体再指定。
#define CHECKSUM_ACCELERATOR_STATUS_REGISTER_OFFSET 0
#define IOADDR_CHECKSUM_ACCELERATOR_STATUS(base)
__IO_CALC_ADDRESS_NATIVE(base,CHECKSUM_ACCELERATOR_STATUS_REGISTER_OFFSET)
#define IORD_CHECKSUM_ACCELERATOR_STATUS(base)
IORD_32DIRECT(base,CHECKSUM_ACCELERATOR_STATUS_REGISTER_OFFSET)
#define IOWR_CHECKSUM_ACCELERATOR_STATUS(base, data)
IOWR_32DIRECT(base, CHECKSUM_ACCELERATOR_STATUS_REGISTER_OFFSET, data)
编写完register map文件后,并可以在HAL API文件中编写API函数,在函数中根据register map文件中的IORD和IOWR宏读写寄存器的值,比如:
alt_u32 read_status_of_checksum(alt_u32 base)
{
return IORD_CHECKSUM_ACCELERATOR_STATUS(base+CHECKSUM_ACCELERATOR_STATUS_REGISTER_OFFSET);
}
上层的软件工程只需要调用API函数及可以操作硬件,而不用直接读写硬件的寄存器,这
也是驱动的主要作用。
用户1690430 2012-8-3 19:03
用户504141 2009-3-19 17:34
用户1332143 2009-1-6 09:46