APB是AMBA中相对比较简单的接口协议。
采用这种简单的协议,你可以轻松地将自定义外设挂在AMBA总线上。
许多APB外设都是慢速器件,例如UART。一般SoC都是通过它们的寄存器进行访问。
下面是一个APB slave 的verilog实例,大家可以在此基础上,设计自己APB slave接口的自定义模块控制器.
// Sample APB register code
// Standard read/write registers
// Adress offset from psel:
// 0x00 : 32 bit read of status32 port
// 0x04 : 32 bit read & write control32 port
// 0x08 : 16 bit status
// and 16 bit read & write control16 port
// 0x0C : 8 bit status8
// and 8 bit read & write control8port
module apb_regs1 (
//system
//APB
//Interface
);
...
endmodule
其中,
// system
input reset_n,
input enable, // clock gating
是系统复位和使能信号
// APB
input pclk,
input [ 3:0] paddr, // ls 2 bits are unused
input pwrite,
input psel,
input penable,
input [31:0] pwdata,
output reg [31:0] prdata,
output pready,
output pslverr,
是APB slave的接口信号
// Interface
input [31:0] status32,
input [15:0] status16,
input [ 7:0] status8,
output reg [31:0] control32,
output reg [15:0] control16,
output reg [ 7:0] control8
是一个自定义模块的寄存器,其中status32是read\_only
wire apb_write = psel & penable &pwrite;
wire apb_read = psel & ~pwrite;
apb\_write和apb\_read是为了满足APB协议做的读写控制。apb\_read信号产生和apb\_write不同,具体原因可以查阅APB协议官方文档
assign pready = 1'b1;
assign pslverr = 1'b0;
该APB slave模块只是对一些控制和状态寄存器进行读写,是无等待传输,同时不生成传输错误信号。
always @(posedge pclk or negedge reset_n)
begin
if (!reset_n)
begin
control32 <= 32'h0;
control16 <= 16'h1234; // reset/initial value
control8 <= 8'h0;
prdata <= 32'h0;
end // reset
else if (enable)
begin
if (apb_write)
begin
case (paddr)
//4'h0 : status32 read only
4'h4 : control32 <= pwdata;
4'h8 : control16 <= pwdata[15:0];
4'hC : control8 <=pwdata[7:0];
endcase
end // write
if (apb_read)
begin
case (paddr)
4'h0 : prdata <= status32;
4'h4 : prdata <= control32;
4'h8 : prdata <= {status16,control16};
4'hC : prdata <={8'h0,status8,8'h0,control8};
endcase
end // read
else
prdata <= 32'h0; // so we can OR all busses
end // clocked
end // always
对不同的寄存器做了地址分配,其中status32寄存器只读
然后我们在Testbench里例化APB slave和一个APB master 模型,对该APB slave模块进行验证。
apb_bus0.read(16'h00,32'h9c4e9a31);
apb_bus0.write(16'h04,32'h11223344);
apb_bus0.write(16'h08,32'hAABB);
apb_bus0.write(16'h0C,32'hDD);
apb_bus0.read(16'h04,32'h11223344);
apb_bus0.read(16'h08,32'h7832AABB);
apb_bus0.read(16'h0C,32'h002a00DD);
本文转载自公众号:芯片数字实验室
原文链接:
https://zhuanlan.zhihu.com/p/84590739
未经作者同意,请勿转载!
推荐阅读
想了解更多内容,欢迎关注Arm ABMA总线专栏