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

AHB2APB设计的更多相关文章

  1. 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑

    阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...

  2. 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成

    阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...

  3. 设计爬虫Hawk背后的故事

    本文写于圣诞节北京下午慵懒的午后.本文偏技术向,不过应该大部分人能看懂. 五年之痒 2016年,能记入个人年终总结的事情没几件,其中一个便是开源了Hawk.我花不少时间优化和推广它,得到的评价还算比较 ...

  4. 如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车

     阅读目录 前言 回顾 梳理 实现 结语 一.前言 之前的文章中已经涉及到了购买商品加入购物车,购物车内购物项的金额计算等功能.本篇准备把剩下的购物车的基本概念一次处理完. 二.回顾 在动手之前我对之 ...

  5. 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念

    一.前言     DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...

  6. 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文

    阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...

  7. 如何一步一步用DDD设计一个电商网站(六)—— 给购物车加点料,集成售价上下文

    阅读目录 前言 如何在一个项目中实现多个上下文的业务 售价上下文与购买上下文的集成 结语 一.前言 前几篇已经实现了一个最简单的购买过程,这次开始往这个过程中增加一些东西.比如促销.会员价等,在我们的 ...

  8. 如何一步一步用DDD设计一个电商网站(五)—— 停下脚步,重新出发

    阅读目录 前言 单元测试 纠正错误,重新出发 结语 一.前言 实际编码已经写了2篇了,在这过程中非常感谢有听到观点不同的声音,借着这个契机,今天这篇就把大家提出的建议一个个的过一遍,重新整理,重新出发 ...

  9. 如何一步一步用DDD设计一个电商网站(四)—— 把商品卖给用户

    阅读目录 前言 怎么卖 领域服务的使用 回到现实 结语 一.前言 上篇中我们讲述了“把商品卖给用户”中的商品和用户的初步设计.现在把剩余的“卖”这个动作给做了.这里提醒一下,正常情况下,我们的每一步业 ...

  10. 如何一步一步用DDD设计一个电商网站(三)—— 初涉核心域

    一.前言 结合我们本次系列的第一篇博文中提到的上下文映射图(传送门:如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念),得知我们这个电商网站的核心域就是销售子域.因为电子商务是以信息网络 ...

随机推荐

  1. 用C#也能做机器学习?

    前言 说到机器学习,大家可能都不陌生,但是用C#来做机器学习,可能很多人还第一次听说.其实在C#中基于ML.NET也是可以做机器学习的,这种方式比较适合.NET程序员在项目中集成机器学习模型,不太适合 ...

  2. XILINX HLS 入坑记录 之 写RAM 综合出 读取+写入Ram

    最近使用 Xilinx HLS 来开发 算法的IPcore,使用的Vitis 2021,发现光是 EDA 工具就存在很多的bug,比如: 1.经常C综合 停留在 Using flow_target ' ...

  3. NetSuite 开发日记 —— 科目类型码

    科目类型码可用于搜索判断科目类型 代码实现 var sch = search.create({ type: 'account', filters: ['type', 'anyof', 'Bank'], ...

  4. 递归产生StackOverflowError

    package com.guoba.digui; public class Demo01 { public void A(){ A();//自己调用自己,递归没用好,产生错误java.lang.Sta ...

  5. MySQL运维实战(1.3)安装部署:源码编译安装

    作者:俊达 引言 在大多数情况下,我们不需要自己编译MySQL源码,因为编译的MySQL和二进制包的内容基本一致.然而,有些特殊情况可能需要我们采用源码编译的方式安装MySQL: 安装非标准版本的My ...

  6. 7.elasticsearch重建索引

    什么时候需要重建索引 索引的mappings发生变更 索引的setting发生变更 集群内,集群间,需要做数据迁移 update by query 在现有索引重建 比如需要给一个text新增一个子字段 ...

  7. mysql将查询结果生成临时表

    MySQL中将查询的结果生成临时表,列类型与查询的列一致,百度搜索到的没啥用. 直接上SQL: 将结果生成临时表 create temporary table temp_tb_name as (sel ...

  8. mybatis空格字符替换

    mybatis空格字符替换 <select id="user" resultType="java.util.Map" parameterType=&quo ...

  9. 解决 git中用vim编写文件时,无法写进文字字母以及光标无法移到最右边的问题

    解决方法:可以切换到英文输入法,然后按'a' 或者 'i'  或者 'o' 或者's'  等.s好像会删掉一个字母.o会使光标移到文末.

  10. 2023-05-31:给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 在你跳跃的过程中,第 1、3、5... 次跳跃称为奇数跳跃 而第 2、4、6... 次跳跃称为偶数跳跃 你可以按以下

    2023-05-31:给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 在你跳跃的过程中,第 1.3.5... 次跳跃称为奇数跳跃 而第 2.4.6... 次跳跃称为偶数跳跃 你可以按以下 ...