当前位置:网站首页>AMBA APB学习记录(AMBA 2.0)
AMBA APB学习记录(AMBA 2.0)
2022-07-31 12:12:00 【IC学习者】
前言
APB自发布以来,已经经过了多个版本的迭代
最初的版本已经过时,目前使用的是三个修订版本
amba 2 版本定义的是最简单的apb
amba 3 相对 2 添加了PREADY/PSLVERR信号
amba 4 相对 3 添加了PPROT/PSTRB信号
本文实现了amba2定义的apb,为了兼容性,将PREADY/PSLVERR信号置为1
主要功能



实现
带状态机的apb
在网上没有找到相应的代码,自己写了一个,感觉要idle状态没有用,就直接用setup和enable状态了
module apb_reg (
input pclk,
input presetn,
input psel,
input pwrite,
input penable,
input [15:0] paddr,
input [31:0] pwdata,
output reg [31:0] prdata,
output pready,
output pslverr,
output reg [31:0] REG_A,
output reg [31:0] REG_B,
output reg [31:0] REG_C,
output reg [31:0] REG_D
);
reg [2:0]state;
reg [2:0]next_state;
localparam setup = 3'b010, enable = 3'b100;
assign pready = 1'b1;
assign pslverr = 1'b1;
always @(posedge pclk, negedge presetn) begin
if(!presetn) begin
state <= setup;
end
else begin
state <= next_state;
end
end
always @(*) begin
case (state)
setup: begin
if(psel)
next_state <= enable;
end
enable: begin
next_state <= setup;
end
default:
next_state <= setup;
endcase
end
always @(*) begin
if(!presetn) begin
REG_A <= 32'h1234_5678;
REG_B <= 32'h234_56789;
REG_C <= 32'h34_56789A;
REG_D <= 32'h4_56789AB;
prdata <= 32'h0;
end
else
case (state)
setup:
if(~pwrite && psel)
// 4字节对齐,低两位忽略
case(paddr[15:2])
14'h0:
prdata <= REG_A;
14'h1:
prdata <= REG_B;
14'h2:
prdata <= REG_C;
14'h3:
prdata <= REG_D;
default:
prdata <= 16'h0;
endcase
enable:begin
if(pwrite && psel && penable)
case(paddr[15:2])
14'h0:
REG_A <= pwdata;
14'h1:
REG_B <= pwdata;
14'h2:
REG_C <= pwdata;
14'h3:
REG_D <= pwdata;
default: ;
endcase
end
default: ;
endcase
end
endmodule
验证
参考:Reference
// https://blog.csdn.net/lyfwill/article/details/106048778
//~ `New testbench
`timescale 1ns / 1ps
module tb_apb_reg;
// apb_reg Parameters
parameter PERIOD = 10;
// apb_reg Inputs
reg pclk = 0 ;
reg presetn = 0 ;
reg psel = 0 ;
reg pwrite = 0 ;
reg penable = 0 ;
reg [15:0] paddr = 0 ;
reg [31:0] pwdata = 0 ;
// apb_reg Outputs
wire [31:0] prdata ;
wire pready ;
wire pslverr ;
wire [31:0] REG_A ;
wire [31:0] REG_B ;
wire [31:0] REG_C ;
wire [31:0] REG_D ;
reg read_valid = 0;
reg [31:0] read_data = 0;
initial
begin
forever #(PERIOD/2) pclk=~pclk;
end
initial
begin
#(PERIOD*2) presetn = 1;
#100; apb_write(16'h00, 16'ha5a5);
#100; apb_write(16'h04, 16'haaaa);
#100; apb_write(16'h08, 16'h5555);
#100; apb_write(16'h0c, 16'h5a5a);
#100; apb_read(16'h00, read_data);
read_valid = 1'b1; #10; read_valid = 1'b0;
#100; apb_read(16'h04, read_data);
read_valid = 1'b1; #10; read_valid = 1'b0;
#100; apb_read(16'h08, read_data);
read_valid = 1'b1; #10; read_valid = 1'b0;
#100; apb_read(16'h0c, read_data);
read_valid = 1'b1; #10; read_valid = 1'b0;
end
reg err_flag;
initial begin
err_flag = 0;
@(posedge read_valid) ;
if(read_data != 16'ha5a5)
err_flag = 1;
@(posedge read_valid) ;
if(read_data != 16'haaaa)
err_flag = 1;
@(posedge read_valid) ;
if(read_data != 16'h5555)
err_flag = 1;
@(posedge read_valid) ;
if(read_data != 16'h5a5a)
err_flag = 1;
#20 ;
$display("-------------------------");
if (err_flag !== 0) begin
$display("Simulation Failed!");
end
else begin
$display("Simulation Succeed!");
end
$display();
$display();
#1000 ;
$finish ;
end
apb_reg u_apb_reg (
.pclk ( pclk ),
.presetn ( presetn ),
.psel ( psel ),
.pwrite ( pwrite ),
.penable ( penable ),
.paddr ( paddr [15:0] ),
.pwdata ( pwdata [31:0] ),
.prdata ( prdata [31:0] ),
.pready ( pready ),
.pslverr ( pslverr ),
.REG_A ( REG_A [31:0] ),
.REG_B ( REG_B [31:0] ),
.REG_C ( REG_C [31:0] ),
.REG_D ( REG_D [31:0] )
);
task apb_write(input [31:0] addr, input [31:0] data); begin
@(negedge pclk);
psel = 1'b1 ;
penable = 1'b0 ;
pwrite = 1'b1 ;
paddr = addr ;
pwdata = data ;
@(posedge pclk);
@(negedge pclk);
penable = 1'b1 ;
@(posedge pclk);
while(pready != 1'b1) @(posedge pclk);
psel = 1'b0 ;
penable = 1'b0 ;
pwrite = 1'b0 ;
paddr = 32'b0 ;
pwdata = 32'b0 ;
repeat (10) @(posedge pclk);
end
endtask //apb_write
task apb_read(input [31:0] addr, output [31:0] data); begin
@(negedge pclk);
psel = 1'b1 ;
penable = 1'b0 ;
pwrite = 1'b0 ;
paddr = addr ;
@(posedge pclk);
@(negedge pclk);
penable = 1'b1 ;
@(posedge pclk);
while(pready != 1'b1) @(posedge pclk);
data = prdata ;
psel = 1'b0 ;
penable = 1'b0 ;
pwrite = 1'b0 ;
paddr = 32'b0 ;
repeat (10) @(posedge pclk);
end
endtask //apb_read
// initial
// begin
// $finish;
// end
endmodule

不带状态机
Reference
虽然使用了pready和pslverr,但是完全兼容 amba 2.0
// reference:https://cloud.tencent.com/developer/article/1642839
// Sample APB register code
// Standard read/write registers
// Adress offset:
// 0x00 : 32 bit read of status32 register
// 0x04 : 32 bit read&write of control32 port
// 0x08 : 16 bit read of status16 register
// 0x0C : 16 bit read&write of control16 register
module apb_reg_nstate (
// APB
input pclk,
input presetn,
input [31:0] paddr,
input pwrite,
input psel,
input penable,
input [31:0] pwdata,
output reg [31:0] prdata,
output pready,
output pslverr
);
reg [31:0] status32 ;
reg [15:0] status16 ;
reg [31:0] control32 ;
reg [15:0] control16 ;
wire apb_write = psel & penable &pwrite;
wire apb_read = psel & ~pwrite;
assign pready = 1'b1;
assign pslverr = 1'b0;
always @(posedge pclk or negedge presetn) begin
if (!presetn) begin
status32 <= 32'h3232;
status16 <= 16'h1616;
control32 <= 32'h0;
control16 <= 16'h0;
prdata <= 32'h0;
end
else if (apb_write) begin
case (paddr)
// 4'h0:status32 read only
4'h4 : control32 <= pwdata;
// 4'h8:status16 read only
4'hC : control16 <=pwdata[15:0];
default: ;
endcase
end
// write
else if (apb_read) begin
case (paddr)
4'h0: prdata <= status32;
4'h4: prdata <= control32;
4'h8: prdata[15:0] <= status16;
4'hC: prdata[15:0] <=control16;
default: ;
endcase
end
end
endmodule
验证
// reference:https://blog.csdn.net/lyfwill/article/details/106048778
//~ `New testbench
`timescale 1ns / 1ps
module tb_apb_reg;
// apb_reg Parameters
parameter PERIOD = 10;
// apb_reg Inputs
reg pclk = 0 ;
reg presetn = 0 ;
reg psel = 0 ;
reg pwrite = 0 ;
reg penable = 0 ;
reg [31:0] paddr = 0 ;
reg [31:0] pwdata = 0 ;
// apb_reg Outputs
wire [31:0] prdata ;
wire pready ;
wire pslverr ;
reg read_valid = 0;
reg [31:0] read_data = 0;
initial
begin
forever #(PERIOD/2) pclk=~pclk;
end
initial
begin
#(PERIOD*2) presetn = 1;
#100; apb_write(16'h00, 16'ha5a5);
#100; apb_write(16'h04, 16'haaaa);
#100; apb_write(16'h08, 16'h5555);
#100; apb_write(16'h0c, 16'h5a5a);
#100; apb_read(16'h00, read_data);
read_valid = 1'b1; #10; read_valid = 1'b0;
#100; apb_read(16'h04, read_data);
read_valid = 1'b1; #10; read_valid = 1'b0;
#100; apb_read(16'h08, read_data);
read_valid = 1'b1; #10; read_valid = 1'b0;
#100; apb_read(16'h0c, read_data);
read_valid = 1'b1; #10; read_valid = 1'b0;
end
reg err_flag;
initial begin
err_flag = 0;
@(posedge read_valid) ;
if(read_data != 16'h3232)
err_flag = 1;
@(posedge read_valid) ;
if(read_data != 16'haaaa)
err_flag = 1;
@(posedge read_valid) ;
if(read_data != 16'h1616)
err_flag = 1;
@(posedge read_valid) ;
if(read_data != 16'h5a5a)
err_flag = 1;
#20 ;
$display("-------------------------");
if (err_flag !== 0) begin
$display("Simulation Failed!");
end
else begin
$display("Simulation Succeed!");
end
$display();
$display();
#1000 ;
$finish ;
end
apb_reg_nstate u_apb_reg (
.pclk ( pclk ),
.presetn ( presetn ),
.psel ( psel ),
.pwrite ( pwrite ),
.penable ( penable ),
.paddr ( paddr [31:0] ),
.pwdata ( pwdata [31:0] ),
.prdata ( prdata [31:0] ),
.pready ( pready ),
.pslverr ( pslverr )
);
task apb_write(input [31:0] addr, input [31:0] data); begin
@(negedge pclk);
psel = 1'b1 ;
penable = 1'b0 ;
pwrite = 1'b1 ;
paddr = addr ;
pwdata = data ;
@(posedge pclk);
@(negedge pclk);
penable = 1'b1 ;
@(posedge pclk);
while(pready != 1'b1) @(posedge pclk);
psel = 1'b0 ;
penable = 1'b0 ;
pwrite = 1'b0 ;
paddr = 32'b0 ;
pwdata = 32'b0 ;
repeat (10) @(posedge pclk);
end
endtask //apb_write
task apb_read(input [31:0] addr, output [31:0] data); begin
@(negedge pclk);
psel = 1'b1 ;
penable = 1'b0 ;
pwrite = 1'b0 ;
paddr = addr ;
@(posedge pclk);
@(negedge pclk);
penable = 1'b1 ;
@(posedge pclk);
while(pready != 1'b1) @(posedge pclk);
data = prdata ;
psel = 1'b0 ;
penable = 1'b0 ;
pwrite = 1'b0 ;
paddr = 32'b0 ;
repeat (10) @(posedge pclk);
end
endtask //apb_read
// initial
// begin
// $finish;
// end
endmodule

reference
AMBA Specification(Rev 2.0)
都看到这儿了,点个赞吧!
||
\/
边栏推荐
猜你喜欢
随机推荐
学习爬虫之Scrapy框架学习(1)---Scrapy框架初学习及豆瓣top250电影信息获取的实战!
JVM 运行时数据区与JMM 内存模型详解
基于姿态估计的护具佩戴检测与动作识别
Use docker to build mysql master-slave
A Week of Wonderful Content Sharing (Issue 14)
ESP8266-Arduino编程实例-HDC1008温度湿度传感器驱动
apisix-Getting Started
Use IN List Population in Your JDBC Application to Avoid Cursor Cache Contention Issues
JVS应用中心
WebGL给Unity传递参数问题1: Cannot read properties of undefined (reading ‘SendMessage‘)
Docker build Mysql master-slave replication
MySQL模糊查询性能优化
WPF中TabControl动态获取当前选中的TabItem
Addition logic for SAP Commerce Cloud Product Review
Encapsulation of conversion between Json and objects (Gson)
CWE4.8 -- The 25 most damaging software security issues in 2022
连续变量离散化教程
[core]-ARMV7-A, ARMV8-A, ARMV9-A Architecture Introduction "Recommended Collection"
dosbox基础使用[通俗易懂]
基于生物激励神经网络的室内实时激光SLAM控制方法









