查看由XPS的向导生成的AXI Lite IP代码模板中,我们能学习到用户自定义IP的结构和实现方式。拿写寄存器来说,我们能看到这样的一段代码
1//implement slave model register(s)
2always@(posedgeBus2IP_Clk )
3begin
4
5if( Bus2IP_Resetn ==1'b0 )
6begin
7slv_reg0 <=0;
8slv_reg1 <=0;
9slv_reg2 <=0;
10slv_reg3 <=0;
11slv_reg4 <=0;
12slv_reg5 <=0;
13slv_reg6 <=0;
14slv_reg7 <=0;
15end
16else
17case( slv_reg_write_sel )
188'b10000000 :
19for( byte_index =0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1)
20if( Bus2IP_BE[byte_index] ==1)
21slv_reg0[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
228'b01000000 :
23for( byte_index =0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1)
24if( Bus2IP_BE[byte_index] ==1)
25slv_reg1[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
268'b00100000 :
27for( byte_index =0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1)
28if( Bus2IP_BE[byte_index] ==1)
29slv_reg2[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
308'b00010000 :
31for( byte_index =0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1)
32if( Bus2IP_BE[byte_index] ==1)
33slv_reg3[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
348'b00001000 :
35for( byte_index =0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1)
36if( Bus2IP_BE[byte_index] ==1)
37slv_reg4[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
388'b00000100 :
39for( byte_index =0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1)
40if( Bus2IP_BE[byte_index] ==1)
41slv_reg5[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
428'b00000010 :
43for( byte_index =0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1)
44if( Bus2IP_BE[byte_index] ==1)
45slv_reg6[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
468'b00000001 :
47for( byte_index =0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1)
48if( Bus2IP_BE[byte_index] ==1)
49slv_reg7[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
50default:begin
51slv_reg0 <=slv_reg0;
52slv_reg1 <=slv_reg1;
53slv_reg2 <=slv_reg2;
54slv_reg3 <=slv_reg3;
55slv_reg4 <=slv_reg4;
56slv_reg5 <=slv_reg5;
57slv_reg6 <=slv_reg6;
58slv_reg7 <=slv_reg7;
59end
60endcase
61
62end//SLAVE_REG_WRITE_PROC
代码实现的功能是将总线上的数据按字节写入到寄存器中。代码中有:
slv_reg0~slv_reg7为8个寄存器
C_SLV_DWIDTH为数据位宽,是一个参数
slv_reg_write_sel为寄存器选择信号,如slv_reg_write_sel = 8‘1000_0000时,slv_reg0将在写操作时被选中。
Bus2IP_Data为写数据端口
Bus2IP_BE为字节使能信号
从这段代码中,我们可以看到:
1、AXI Lite 从设备接口也是memory mapped的,但不像AVALON memory mapped 。一个从设备的基地址C_BASEADDR设定后,设备的寄存器是通过Bus2IP_WrCE / Bus2IP_RdCE 信号(这里即slv_reg_write_sel) 信号选择的。当然,slv_reg_write_sel 信号的编码源是地址线,AXI Lite 规定最高位为1时的基地址,在这里slv_reg_write_sel 为8’b1000_0000,寄存器slv_reg0地址就是基地址;slv_reg_write_sel 为8’b0100_0000,寄存器slv_reg1地址就是基地址+0x04;以此类推。从设备的地址空间由参数设定,而不是由地址线直接决定。
2、对于寄存器中的字节,代码是这样实现
1for( byte_index =0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1)
2if( Bus2IP_BE[byte_index] ==1)
3slv_reg3[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
假如数据宽度C_SLV_DWIDTH是32bit,那么把参数用数字代入后,代码是这样的
1for( byte_index =0; byte_index <= 3; byte_index = byte_index+1)
2if( Bus2IP_BE[byte_index] ==1)
3slv_reg3[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
很好理解,就是字节使能Bus2IP_BE对应为有效,则将对应字节从数据总线传输到相应寄存器上。能看到XPS生成的模板,很巧妙的用到了这样的表达式
slv_reg3[(byte_index*8) +:8] <= Bus2IP_Data[(byte_index*8) +:8];
形式即为
a[startbit+:8] <= b[startbit +:8];
8为长度,等效为
a[startbit+7: startbit] <= b[startbit+7: startbit]
这种简略写法可以在以后的编程中参考