【IC每日一题:AMBA总线--APB协议时序及Verilog实现】
AMBA总线--APB协议时序及Verilog实现
- 1 APB3协议
- 1.1 APB3时序
- 1.1.1 APB写操作
- 1.1.2 APB读操作
- 2 代码
- 2.1 apb_master
- 2.2 apb_slave
【博客首发于微信公众号《漫谈芯片与编程》,欢迎专注一下,多谢大家】
AMBA总线是用于连接微控制器和外围设备的总线协议,由ARM公司提出的一种片上系统SoC互联标准。
AMBA总线协议家族主要包括:APB、AHB、AXI、ACI、CHI协议;其中后两个协议主要是专门为了缓存一致性;
本篇博客主要介绍 APB3协议;
1 APB3协议
APB3协议:APB用来实现与外围设备进行通信–一般用来配置寄存器;APB协议是一主多从,唯一的master一般是apb_bridge模块;
总体特点:低功耗、低带宽、无流水线结构、每次传输至少需要两个时钟周期;
1.1 APB3时序
在这里会分别给出有等待和无等待的时序图做对比,在项目中主要还是用的有等待时序图;
什么是无等待:即slave会直接在maste拉高penable时进行拉高,只维持一个周期;
什么是有等待:即slave会跟自己内部业务进行任意时刻拉高pready,而在此期间以上master的信号都要维持不变;
1.1.1 APB写操作
【描述】
1.T0周期(T0-T1):IDLE状态;
2.T1周期(T1-T2):master提前准备好pasel,paddr,pwrite,pwdata;
3.T2周期(T2-T3):master拉高penable,告知当前数据有效,进行采样传输;
–>T3周期(T3-T4):是代表数据传输结束,回到IDLE状态;
1.1.2 APB读操作
T0周期:IDLE状态;
T1周期:master提前准备好psel,paddr,pwrite;
T2周期:在无等待模式下:slave准备好prdate并拉高pready;当然在有等待模式下,pready可以继续没准备好,当pready准备好拉高后,prdata同时返回并有效;
2 代码
从前面系列篇可知:对待时序,我们尽量用状态机来设计指导编码;
在这里官方给出状态机:正好对应上面时序图上的周期;
IDLE:deault state;
SetUp:psel立刻拉高,相关信号在setup阶段准备好,并且下一周期就立刻转移到下一状态;
Access:penable在该状态拉高,相关信号paddr,pwrite,psel,pwdata等在这保持;
2.1 apb_master
在这里实现一个apb_master的代码示例:
/*-------------------------------------------------------------
-- modified by xlinxdu, 2022/05/27
-- pclk 50MHz
-- APB3,No pslverr signal
-- cmd_i:56bit;[55:48]:r/w ,8'b0 -> read,8'b1 -> write[47:32]:paddr ,[31:0]:pwdata
-------------------------------------------------------------*/
module apb
#(parameter RD_FLAG = 8'b0 ,parameter WR_FLAG = 8'b1 ,parameter CMD_RW_WIDTH = 8 ,parameter CMD_ADDR_WIDTH = 16 ,parameter CMD_DATA_WIDTH = 32 ,parameter CMD_WIDTH = CMD_RW_WIDTH + CMD_ADDR_WIDTH + CMD_DATA_WIDTH
)(
//-- system signalinput pclk_i ,input prst_n_i ,//-- cmd_ininput [CMD_WIDTH-1:0] cmd_i ,input cmd_vld_i ,output reg [CMD_DATA_WIDTH-1:0] cmd_rd_data_o,//-- apb interfaceoutput reg [CMD_ADDR_WIDTH-1:0] paddr_o ,output reg pwrite_o ,output reg psel_o ,output reg penable_o ,output reg [CMD_DATA_WIDTH-1:0] pwdata_o ,input [CMD_DATA_WIDTH-1:0] prdata_i ,input pready_i ,input pslverr_i
);//-- FSM state
parameter IDLE = 3'b001;
parameter SETUP = 3'b010;
parameter ACCESS = 3'b100;//-- current state and next state
reg [2:0] cur_state;
reg [2:0] nxt_state;//-- data buf
reg start_flag ;
reg [CMD_WIDTH-1:0] cmd_in_buf ;
reg [CMD_DATA_WIDTH-1:0] cmd_rd_data_buf;/*-----------------------------------------------\-- update cmd_in_buf --
\-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) beginif (!prst_n_i) begincmd_in_buf <= {(CMD_WIDTH){1'b0}};endelse if (cmd_vld_i && pready_i) begincmd_in_buf <= cmd_i;end
end/*-----------------------------------------------\-- start flag of transfer --
\-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) beginif (!prst_n_i) beginstart_flag <= 1'b0;endelse if (cmd_vld_i && pready_i) beginstart_flag <= 1'b1;endelse beginstart_flag <= 1'b0;end
end/*-----------------------------------------------\-- update current state --
\-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) beginif (!prst_n_i) begincur_state <= IDLE;endelse begincur_state <= nxt_state;end
end/*-----------------------------------------------\-- update next state --
\-----------------------------------------------*/
always @ (*) begincase(cur_state)IDLE :if(start_flag)beginnxt_state = SETUP;endelse beginnxt_state = IDLE;endSETUP :nxt_state = ACCESS;ACCESS:if (!pready_i)beginnxt_state = ACCESS;endelse if(start_flag)beginnxt_state = SETUP;endelse if(!cmd_vld_i && pready_i)beginnxt_state = IDLE;endendcase
end/*-----------------------------------------------\-- update signal of output --
\-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) beginif (!prst_n_i) beginpwrite_o <= 1'b0;psel_o <= 1'b0;penable_o <= 1'b0;paddr_o <= {(CMD_ADDR_WIDTH){1'b0}};pwdata_o <= {(CMD_DATA_WIDTH){1'b0}};endelse if (nxt_state == IDLE) beginpsel_o <= 1'b0;penable_o <= 1'b0;endelse if(nxt_state == SETUP)beginpsel_o <= 1'b1;penable_o <= 1'b0;paddr_o <= cmd_in_buf[CMD_WIDTH-CMD_RW_WIDTH-1:CMD_DATA_WIDTH];//-- readif(cmd_in_buf[CMD_WIDTH-1:CMD_WIDTH-8] == RD_FLAG)beginpwrite_o <= 1'b0;end//-- writeelse beginpwrite_o <= 1'b1;pwdata_o <= cmd_in_buf[CMD_DATA_WIDTH-1:0];endendelse if(nxt_state == ACCESS)beginpenable_o <= 1'b1;end
end/*-----------------------------------------------\-- update cmd_rd_data_buf --
\-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) beginif (!prst_n_i) begincmd_rd_data_buf <= {(CMD_DATA_WIDTH){1'b0}};endelse if (pready_i && psel_o && penable_o) begincmd_rd_data_buf <= prdata_i;end
end/*-----------------------------------------------\-- update cmd_rd_data_o --
\-----------------------------------------------*/
always @ (posedge pclk_i or negedge prst_n_i) beginif (!prst_n_i) begincmd_rd_data_o <= {(CMD_DATA_WIDTH){1'b0}};endelse begincmd_rd_data_o <= cmd_rd_data_buf;end
endendmodule
2.2 apb_slave
在这里实现一个apb_slave读写寄存器的Demo;
`timescale 1ns/100psmodule apb_slave #(parameter AW = 32,//地址总线宽度parameter DW = 32 //数据总线宽度) (//systeminput reset_n,//apb_interfaceinput pclk, //时钟input [AW-1:0] paddr, //地址input pwrite, //读/写控制信号input psel, //选择信号input penable, //使能信号input [DW-1:0] pwdata, //写(输入)数据output reg [DW-1:0] prdata, //读(输出)数据output reg pready, //传输完成标志,low未完成,high完成output reg pslverr //错误标志,high出现错误);
//apb状态机
parameter IDLE = 2'b00;
parameter SETUP = 2'b01;
parameter ACCESS = 2'b10;
reg [1:0] state_now = 2'b00;
reg [1:0] state_next = 2'b00;//映射到总线上的寄存器
reg [31:0] readonly32; //0x10000000,只可读
reg [15:0] readonly16; //0x10000004,只可读
reg [31:0] readwrite32; //0x10000008,可读可写
reg [15:0] readwrite16; //0x1000000C,可读可写always @(posedge pclk or negedge reset_n) begin: init_and_change_stateif (!reset_n) beginpready <= 1'b0;pslverr <= 1'b0;prdata <= 32'h0;readwrite32 <= 32'h0;readwrite16 <= 16'h0;readonly32 <= 32'h12345678;readonly16 <= 16'habcd;state_now <= IDLE;endelse beginstate_now <= state_next;end
end//! fsm_extract
always @(posedge pclk) begin :main_fsm_of_apbcase (state_now)IDLE: begin //IDLE状态case (psel)1'b1: state_next <= SETUP; //选择本apb外设,进入setup状态1'b0: state_next <= IDLE;default: state_next <= IDLE;endcaseendSETUP: begin//SETUP状态case (psel)1'b1: begincase (penable)1'b1: state_next <= ACCESS;//选中且enable信号拉高,进入ACCESS模式传输数据1'b0: state_next <= SETUP;default: state_next <= SETUP;endcaseend1'b0: state_next <= IDLE; //未被选中,回到IDLEdefault: state_next <= IDLE;endcasepready <= 1'b0;endACCESS: begin //ACCESS状态,根据寄存器地址读写prdata <= 32'h0;pslverr <= 1'b0;if (pwrite) begin //wirte信号拉高,写入模式case (paddr)32'h10000008: begin readwrite32 <= pwdata; pready <= 1'b1; end//数据传输完成 32'h1000000C: begin readwrite16 <= pwdata[15:0]; pready <= 1'b1; end//数据传输完成 default: pslverr <= 1'b1;endcaseendelse if(!pwrite) begin //write信号拉低,读取模式case (paddr)32'h10000000: begin prdata <= readonly32; pready <= 1'b1; end//数据传输完成 32'h10000004: begin prdata <= readonly16; pready <= 1'b1; end//数据传输完成 32'h10000008: begin prdata <= readwrite32; pready <= 1'b1; end//数据传输完成 32'h1000000C: begin prdata <= readwrite16; pready <= 1'b1; end//数据传输完成 default: pslverr <= 1'b1;endcaseendif (pready) begincase (psel)1'b1: state_next <= SETUP; //不需要传输数据,回到SETUP1'b0: state_next <= IDLE; //未被选中,回到IDLEdefault: state_next <= IDLE;endcaseendelse state_next <= ACCESS; //需要继续传输数据,则回到ACCESS enddefault: state_next <= IDLE;endcase
end
endmodule
[ref]
1.https://blog.csdn.net/qq_43244515/article/details/124968189
2.https://www.amghank.cn/2021/08/24/CORE%E5%AD%A6%E4%B9%A0%EF%BC%9AAMBA3–APB%E6%80%BB%E7%BA%BF%E5%8D%8F%E8%AE%AE%E5%8F%8A%E7%AE%80%E5%8D%95%E4%BE%8B%E5%AD%90/
相关文章:

【IC每日一题:AMBA总线--APB协议时序及Verilog实现】
AMBA总线--APB协议时序及Verilog实现 1 APB3协议1.1 APB3时序1.1.1 APB写操作1.1.2 APB读操作 2 代码2.1 apb_master2.2 apb_slave 【博客首发于微信公众号《漫谈芯片与编程》,欢迎专注一下,多谢大家】 AMBA总线是用于连接微控制器和外围设备的总线协议&…...

抢先看!为什么很多公司会强行给员工电脑加屏幕水印?千字长文来解答
2024年度热议:为什么很多公司会强行给员工电脑加屏幕水印? 有人说:概是为了让员工时刻铭记,工作就像这水印,无处不在,想逃也逃不掉! “玩归玩,闹归闹”。 本文将对此进行详尽解答&…...
【AI技术】PaddleSpeech部署方案
【AI技术】PaddleSpeech部署方案 技术介绍优点缺点 部署基础环境的搭建分步详解国内镜像源切换所需环境1 g所需环境2 vim所需环境3 cuda所需环境4 cudnn所需环境5 ssl源码拉取PaddleSpeech环境安装 部署文件分享DockerHub 技术介绍 PaddleSpeech是飞浆平台的一款TTS框架。 优…...

可灵开始“独闯”,全面拥抱AI的快手能否尝到“甜头”?
现任谷歌CEO桑达尔皮查伊曾说到,“人工智能是我们人类正在从事的最为深刻的研究方向之一,甚至要比火与电还更加深刻。” 正如,Sora诞生时,在官方表述中被称为“世界模拟器”,它理解真实的规则,并在此基础上…...

qt QtConcurrent 详解
1、概述 QtConcurrent是Qt框架中用于简化多线程编程的一个模块,它提供了高层次的API来实现并行计算,而不需要开发者直接管理线程的创建、调度和销毁。QtConcurrent主要通过QFuture和QThreadPool来进行并发任务的执行,能够自动利用系统的所有…...
基于构件的软件开发、软件维护、区块链技术及湖仓一体架构的应用
目录 试题一 论基于构件的软件开发方法及其应用 试题二 论软件维护方法及其应用 试题三 论区块链技术及应用 试题四 论湖仓一体架构及其应用 相关推荐 试题一 论基于构件的软件开发方法及其应用 基于构件的软件开发(Component-Based Software Development,CBSD…...
【在Typora中绘制用户旅程图和甘特图】
在 Typora 中可以使用 Mermaid 绘制用户旅程图(User Journey Map),但由于 Mermaid 并不直接支持用户旅程图,我们可以通过一些图表的变通方式(比如流程图或甘特图)来表示用户旅程图的结构。用户旅程图通常展…...

【Vue3】知识汇总,附详细定义和源码详解,后续出微信小程序项目(2)
快速跳转: 我的个人博客主页👉:Reuuse博客 新开专栏👉:Vue3专栏 参考文献👉:uniapp官网 ❀ 感谢支持!☀ 前情提要 🔺因为最近学习的vue语言,发现有很多细节…...
uniapp中使用全局样式文件引入的三种方式
如果你想在 uni-app 中全局引入 SCSS 文件(例如 global.scss),可以通过以下步骤进行配置: 方法一:在 main.js 中引入 在 main.js 中引入全局样式: 你可以在 src/main.js 文件中直接引入 SCSS 文件ÿ…...
计算机网络易混淆知识点串记
文章目录 计算机网络易混淆知识点串记各层PDU首部: 计算机网络易混淆知识点串记 各层PDU首部: PUD首部长度 (B:字节)首部单位数据链路–帧帧首:14B帧尾部:4B——IPV420~60字节4B [通过4位二进制表示]IPV6固定首部40字节[可拓展]4BTCP20~60字节4BUDP8B字节...

Java代码审计-模板注入漏洞
一、模板引擎 在Java开发当中,为了将前端和后端进行分离,降低项目代码的耦合性,使代码更加易于维护和管理。除去以上的原因,模板引擎还能实现动态和静态数据的分离。 二、主流模板引擎 在Java中,主流的模板引擎有:Fre…...

如何在Linux中使用Cron定时执行SQL任务
文章目录 前言一、方案分析二、使用步骤1.准备脚本2.crontab脚本执行 踩坑 前言 演示数据需要每天更新监控数据,不想手动执行,想到以下解决方案 navicat 创建定时任务java服务定时执行linux crontab 定时执行sql脚本 一、方案分析 我选择了第三个方案…...

数据集划分
1、 sklearn玩具数据集介绍 数据量小,数据在sklearn库的本地,只要安装了sklearn,不用上网就可以获取 2 sklearn现实世界数据集介绍 数据量大,数据只能通过网络获取(科学上网) 3 sklearn加载玩具数据集 示…...

带你读懂什么是AI Agent智能体
一、智能体的定义与特性 定义:智能体是一个使用大语言模型(LLM)来决定应用程序控制流的系统。然而,智能体的定义并不唯一,不同人有不同的看法。Langchain的创始人Harrison Chase从技术角度给出了定义,但更…...
react动态路由
在React应用中,动态路由(Dynamic Routing)通常指的是根据应用的状态或用户的交互来动态地显示或隐藏路由(页面或组件)。这可以通过多种方法实现,包括使用React Router库,它提供了强大的路由管理…...

Linux基础(十四)——BASH
BASH 1.BASH定义2.shell的种类3.bash的功能3.1 命令记录功能3.2 命令补全功能3.3 命令别名设置3.4 工作控制、 前景背景控制3.5 程序化脚本: ( shell scripts)3.6 万用字符 4.bash的内置命令5.shell的变量功能5.1 变量的取用5.2 新建变量5.3 …...
架构师备考-概念背诵(系统架构)
软件架构概念 一个程序和计算系统软件体系结构是指系统的一个或者多个结构。结构中包括软件的构件,构件的外部可见属性以及它们之间的相互关系。体系结构并非可运行软件。确切地说,它是一种表达,使软件工程师能够: (1)分析设计在满足所规定的需求方面的有效性:(2)在设计变…...

如何让ffmpeg运行时从当前目录加载库,而不是从/lib64
程序在linux下运行时,一般从 /lib64 目录下加载依赖的库文件,如xxx.so. 有时候,系统里没有这些库,也不想从系统目录下加载,怎么办呢? 看下面的调整过程。 使用的源代码是 ffmpeg-6.1.tar.xz 解压后&…...
Kafka-Controller选举
一、上下文 《Kafka-broker粗粒度启动流程》博客中我们分析了broker的大致启动流程,这个时候每个broker都不是controller角色,下面我们就来看下它是如何选举出来的吧 二、设置ZooKeeper ZooKeeper是一个开源的分布式协调服务,主要用于分…...

必知的 Vue3 组件传值技巧:解锁组件交互新姿势
父传子defineProps 基本概念 在 Vue 3 中,父传子是一种组件间通信的方式,用于将父组件的数据传递给子组件。这种通信方式可以让组件之间更好地协作,实现功能的复用和模块的划分。 实现步骤 在父组件中传递数据 App.vue <template>…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...