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
AHB2APB设计的更多相关文章
- 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑
阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...
- 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成
阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...
- 设计爬虫Hawk背后的故事
本文写于圣诞节北京下午慵懒的午后.本文偏技术向,不过应该大部分人能看懂. 五年之痒 2016年,能记入个人年终总结的事情没几件,其中一个便是开源了Hawk.我花不少时间优化和推广它,得到的评价还算比较 ...
- 如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车
阅读目录 前言 回顾 梳理 实现 结语 一.前言 之前的文章中已经涉及到了购买商品加入购物车,购物车内购物项的金额计算等功能.本篇准备把剩下的购物车的基本概念一次处理完. 二.回顾 在动手之前我对之 ...
- 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念
一.前言 DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...
- 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文
阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...
- 如何一步一步用DDD设计一个电商网站(六)—— 给购物车加点料,集成售价上下文
阅读目录 前言 如何在一个项目中实现多个上下文的业务 售价上下文与购买上下文的集成 结语 一.前言 前几篇已经实现了一个最简单的购买过程,这次开始往这个过程中增加一些东西.比如促销.会员价等,在我们的 ...
- 如何一步一步用DDD设计一个电商网站(五)—— 停下脚步,重新出发
阅读目录 前言 单元测试 纠正错误,重新出发 结语 一.前言 实际编码已经写了2篇了,在这过程中非常感谢有听到观点不同的声音,借着这个契机,今天这篇就把大家提出的建议一个个的过一遍,重新整理,重新出发 ...
- 如何一步一步用DDD设计一个电商网站(四)—— 把商品卖给用户
阅读目录 前言 怎么卖 领域服务的使用 回到现实 结语 一.前言 上篇中我们讲述了“把商品卖给用户”中的商品和用户的初步设计.现在把剩余的“卖”这个动作给做了.这里提醒一下,正常情况下,我们的每一步业 ...
- 如何一步一步用DDD设计一个电商网站(三)—— 初涉核心域
一.前言 结合我们本次系列的第一篇博文中提到的上下文映射图(传送门:如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念),得知我们这个电商网站的核心域就是销售子域.因为电子商务是以信息网络 ...
随机推荐
- 用C#也能做机器学习?
前言 说到机器学习,大家可能都不陌生,但是用C#来做机器学习,可能很多人还第一次听说.其实在C#中基于ML.NET也是可以做机器学习的,这种方式比较适合.NET程序员在项目中集成机器学习模型,不太适合 ...
- XILINX HLS 入坑记录 之 写RAM 综合出 读取+写入Ram
最近使用 Xilinx HLS 来开发 算法的IPcore,使用的Vitis 2021,发现光是 EDA 工具就存在很多的bug,比如: 1.经常C综合 停留在 Using flow_target ' ...
- NetSuite 开发日记 —— 科目类型码
科目类型码可用于搜索判断科目类型 代码实现 var sch = search.create({ type: 'account', filters: ['type', 'anyof', 'Bank'], ...
- 递归产生StackOverflowError
package com.guoba.digui; public class Demo01 { public void A(){ A();//自己调用自己,递归没用好,产生错误java.lang.Sta ...
- MySQL运维实战(1.3)安装部署:源码编译安装
作者:俊达 引言 在大多数情况下,我们不需要自己编译MySQL源码,因为编译的MySQL和二进制包的内容基本一致.然而,有些特殊情况可能需要我们采用源码编译的方式安装MySQL: 安装非标准版本的My ...
- 7.elasticsearch重建索引
什么时候需要重建索引 索引的mappings发生变更 索引的setting发生变更 集群内,集群间,需要做数据迁移 update by query 在现有索引重建 比如需要给一个text新增一个子字段 ...
- mysql将查询结果生成临时表
MySQL中将查询的结果生成临时表,列类型与查询的列一致,百度搜索到的没啥用. 直接上SQL: 将结果生成临时表 create temporary table temp_tb_name as (sel ...
- mybatis空格字符替换
mybatis空格字符替换 <select id="user" resultType="java.util.Map" parameterType=&quo ...
- 解决 git中用vim编写文件时,无法写进文字字母以及光标无法移到最右边的问题
解决方法:可以切换到英文输入法,然后按'a' 或者 'i' 或者 'o' 或者's' 等.s好像会删掉一个字母.o会使光标移到文末.
- 2023-05-31:给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 在你跳跃的过程中,第 1、3、5... 次跳跃称为奇数跳跃 而第 2、4、6... 次跳跃称为偶数跳跃 你可以按以下
2023-05-31:给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 在你跳跃的过程中,第 1.3.5... 次跳跃称为奇数跳跃 而第 2.4.6... 次跳跃称为偶数跳跃 你可以按以下 ...