AHB2APB设计
AHB2APB Bridge位置
- AHB子系统时钟在200Mhz左右,APB时钟在几十Khz到几十Mhz
- 所以要进行跨时钟域处理,从AHB高时钟频率转到APB低时钟频率
AHB2APB Bridge规格说明
- Bridge是APB总线上唯一的主机(也可以通过设计使APB支持多个Master)
AHB2APB Bridge接口
- Bridge是连接AHB总线和APB总线的桥梁,所以接口有AHB总线和APB总线
- Bridge是APB总线的Master,是AHA的Slave
- psel - 有多少个外设就有多少个psel信号
- penable - 时钟选通信号
AHB2APB Bridge状态机
- Bridge开始的时候处于IDLE状态,当Bridge收到AHB总线的传输信号之后,进入到setup状态,在setup状态将AHB控制和地址信号进行锁存并将psel置于1,进入到enable状态,可以进行apb的读写操作
AHB2APB Bridge读时序
AHB2APB Bridge 写时序
AHB2APB Bridge设计
设计规格
- 对于输入输出数据进行寄存或者不寄存,由模块控制,主要是为了时序
接口信号
- APBACTIVE - APB激活信号
状态机1:输入输出不寄存
状态机2:输入输出数据寄存
状态机:发生传输错误
RTL
module ahb_to_apb_bridge
#(
parameter ADDRWIDTH = 16 ,
parameter REGISTER_RDATA = 1,
parameter REGISTER_WDATA = 0
)
(
input wire hclk,
input wire hresetn,
input wire pclken,
input wire hsel,
input wire [ADDRWIDTH-1:0] haddr,
input wire [1:0] htrans,
input wire [2:0] hsize,
input wire [4:0] hprot,
input wire hwrite,
input wire hready,
input wire [31:0] hwdata,
output reg hreadyout,
output wire [31:0] hrdata,
output wire hresp,
output wire [ADDRWIDTH-1:0] paddr,
output wire penable,
output wire pwrite,
output wire [3:0] pstrb,
output wire [2:0] pprot,
output wire [31:0] pwdata,
output wire psel,
output wire apbactive,
input wire [31:0] prdata,
input wire pready,
input wire pslverr
);
// 寄存写信号和写地址
reg [ADDRWIDTH-1:0] addr_reg;
reg [2:0] wr_reg;
reg [31:0] rwdata_reg;
// 定义当前状态变量和下一状态变量
reg [2:0] state_reg;
reg [2:0] next_state;
reg [3:0] pstrb_reg;
wire [3:0] pstrb_nxt;
reg [1:0] pprot_reg;
wire [1:0] pprot_nxt;
// apb bridge选择信号
wire apb_select;
// 传输完成信号
wire apb_tran_end;
// 判断数据是否寄存的变量
wire reg_rdata_cfg;
wire reg_wdata_cfg;
// 定义写控制信号寄存的寄存器
reg sample_wdata_reg;
localparam ST_BITS=3;
localparam [ST_BITS-1:0] ST_IDLE =3'b000;
localparam [ST_BITS-1:0] ST_APB_WAIT =3'b001;
localparam [ST_BITS-1:0] ST_APB_TRNF =3'b010;
localparam [ST_BITS-1:0] ST_APB_TRNF2 =3'b011;
localparam [ST_BITS-1:0] ST_APB_NODOK =3'b100;
localparam [ST_BITS-1:0] ST_APB_ERR1 =3'b101;
localparam [ST_BITS-1:0] ST_APB_ERR2 =3'b110;
localparam [ST_BITS-1:0] ST_APB_ILLEGAL =3'b111;
// main code
// 产生读写数据是否寄存的信号
assign reg_rdata_cfg = REGISTER_RDATA == 0? 1'b0 : 1'b1;
assign reg_rdata_cfg = REGISTER_WDATA == 0? 1'b0 : 1'b1;
// 产生bridge被选中的信号
assign apb_select = hsel && htrans[1] && hready;
// apb传输完成信号
assign apb_tran_end = (state_reg == 3'b011) & pready;
//pprot信号产生
assign pprot_nxt[0] = hprot[1];
assign pprot_nxt[1] = ~hprot[0];
// pstrb信号产生
assign pstrb_nxt[0] = hwrite & ((hsize[1]) |(hsize[0] & (~haddr[1])) | (haddr[1:0]==2'b00));
assign pstrb_nxt[1] = hwrite & ((hsize[1]) |(hsize[0] & (~haddr[1])) | (haddr[1:0]==2'b01));
assign pstrb_nxt[2] = hwrite & ((hsize[1]) |(hsize[0] & haddr[1]) | (haddr[1:0]==2'b10));
assign pstrb_nxt[3] = hwrite & ((hsize[1]) |(hsize[0] & haddr[1]) | (haddr[1:0]==2'b11));
// sample control signals 打拍信号
// data和addr对齐
always @(posedge hclk or negedge hresetn) begin
if(!hresetn) begin
addr_reg <= {ADDRWIDTH-2{1'b0}};
wr_reg <= 1'b0;
pprot_reg <= 2'b0;
pstrb_reg <= 4'b0;
end
else if(apb_select) begin
addr_reg <= haddr[ADDRWIDTH-1:2];
wr_reg <= hwrite;
pprot_reg <= pprot_nxt;
pstrb_reg <= pstrb_nxt;
end
end
// 采样写数据的控制信号
wire sample_wdata_set = apb_select & hwrite & reg_wdata_cfg;
wire sample_wdata_clt = sample_wdata_set & pclken;
always @ (posedge hclk or negedge hresetn) begin
if(!hresetn) begin
sample_wdata_reg <= 1'b0;
end
else if(sample_wdata_set | sample_wdata_clt) begin
sample_wdata_reg <= sample_wdata_set;
end
end
// 第一段状态机
always @ (posedge hclk or negedge hresetn) begin
if(!hresetn) begin
state_reg <= 3'b000;
end
else
state_reg <= next_state;
end
// 第二段状态机描述状态转移
always @ (*) begin
case(state_reg)
ST_IDLE:
begin
if(apb_select & pclken & ~(reg_wdata_cfg&hwrite)) begin
next_state = ST_APB_TRNF;
end
else if(apb_select)
next_state = ST_APB_WAIT;
else
next_state = ST_IDLE;
end
ST_APB_WAIT:
begin
if(pclken)
next_state = ST_APB_TRNF;
else
next_state = ST_IDLE;
end
ST_APB_TRNF:
begin
if(pclken)
next_state = ST_APB_TRNF2;
else
next_state = ST_APB_TRNF;
end
ST_APB_TRNF2:
begin
if(pready & pslverr & pclken)
next_state = ST_APB_ERR1;
else if(pready & (~pslverr)&pclken)
begin
if(reg_rdata_cfg)
next_state = ST_APB_NODOK;
else
next_state = ST_APB_TRNF2;
end
end
ST_APB_NODOK:
begin
if(apb_select & pclken & ~(reg_wdata_cfg&hwrite)) begin
next_state = ST_APB_TRNF;
end
else if(apb_select)
next_state = ST_APB_WAIT;
else
next_state = ST_IDLE;
end
ST_APB_ERR1:
next_state = ST_APB_ERR2;
ST_APB_ERR2:
if(apb_select & pclken & ~(reg_wdata_cfg&hwrite)) begin
next_state = ST_APB_TRNF;
end
else if(apb_select)
next_state = ST_APB_WAIT;
else
next_state = ST_IDLE;
default : next_state = 3'bxxx;
endcase
end
// 采样数据
always @ (posedge hclk or negedge hresetn) begin
if(!hresetn)
rwdata_reg = 32'b0;
else if(sample_wdata_reg & reg_wdata_cfg & pclken)
rwdata_reg <= hwdata;
else if(apb_tran_end & reg_rdata_cfg & pclken)
rwdata_reg <= prdata;
end
// 产生输出信号
assign paddr = {addr_reg,2'b00};
assign pwrite = wr_reg;
assign pwdata = reg_wdata_cfg ? rwdata_reg : hwdata;
assign psel = (state_reg == ST_APB_TRNF | state_reg == ST_APB_TRNF2);
assign penable = (state_reg == ST_APB_TRNF2);
assign pprot = {pprot_reg[1],1'b0,pprot_reg[0]};
assign pstrb = pstrb_reg[3:0];
//产生hready_out
always @(*) begin
case(state_reg)
ST_IDLE:hreadyout = 1'b1;
ST_APB_WAIT:hreadyout=1'b0;
ST_APB_TRNF:hreadyout=1'b0;
ST_APB_TRNF2:hreadyout=(~reg_rdata_cfg) & pready & (~pslverr)&pclken;
ST_APB_NODOK:hreadyout = 1'b0;
ST_APB_ERR1:hreadyout = 1'b0;
ST_APB_ERR1:hreadyout = 1'b1;
default:hreadyout=1'bx;
endcase
end
assign hrdata = reg_rdata_cfg ? rwdata_reg : prdata;
assign hresp = (state_reg == ST_APB_ERR1) |(state_reg == ST_APB_ERR2);
assign apbactive = (hsel & htrans[1]) | state_reg;
endmodule