当前位置: 首页 > news >正文

【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 【博客首发于微信公众号《漫谈芯片与编程》&#xff0c;欢迎专注一下&#xff0c;多谢大家】 AMBA总线是用于连接微控制器和外围设备的总线协议&…...

抢先看!为什么很多公司会强行给员工电脑加屏幕水印?千字长文来解答

2024年度热议&#xff1a;为什么很多公司会强行给员工电脑加屏幕水印&#xff1f; 有人说&#xff1a;概是为了让员工时刻铭记&#xff0c;工作就像这水印&#xff0c;无处不在&#xff0c;想逃也逃不掉&#xff01; “玩归玩&#xff0c;闹归闹”。 本文将对此进行详尽解答&…...

【AI技术】PaddleSpeech部署方案

【AI技术】PaddleSpeech部署方案 技术介绍优点缺点 部署基础环境的搭建分步详解国内镜像源切换所需环境1 g所需环境2 vim所需环境3 cuda所需环境4 cudnn所需环境5 ssl源码拉取PaddleSpeech环境安装 部署文件分享DockerHub 技术介绍 PaddleSpeech是飞浆平台的一款TTS框架。 优…...

可灵开始“独闯”,全面拥抱AI的快手能否尝到“甜头”?

现任谷歌CEO桑达尔皮查伊曾说到&#xff0c;“人工智能是我们人类正在从事的最为深刻的研究方向之一&#xff0c;甚至要比火与电还更加深刻。” 正如&#xff0c;Sora诞生时&#xff0c;在官方表述中被称为“世界模拟器”&#xff0c;它理解真实的规则&#xff0c;并在此基础上…...

qt QtConcurrent 详解

1、概述 QtConcurrent是Qt框架中用于简化多线程编程的一个模块&#xff0c;它提供了高层次的API来实现并行计算&#xff0c;而不需要开发者直接管理线程的创建、调度和销毁。QtConcurrent主要通过QFuture和QThreadPool来进行并发任务的执行&#xff0c;能够自动利用系统的所有…...

基于构件的软件开发、软件维护、区块链技术及湖仓一体架构的应用

目录 试题一 论基于构件的软件开发方法及其应用 试题二 论软件维护方法及其应用 试题三 论区块链技术及应用 试题四 论湖仓一体架构及其应用 相关推荐 试题一 论基于构件的软件开发方法及其应用 基于构件的软件开发(Component-Based Software Development&#xff0c;CBSD…...

【在Typora中绘制用户旅程图和甘特图】

在 Typora 中可以使用 Mermaid 绘制用户旅程图&#xff08;User Journey Map&#xff09;&#xff0c;但由于 Mermaid 并不直接支持用户旅程图&#xff0c;我们可以通过一些图表的变通方式&#xff08;比如流程图或甘特图&#xff09;来表示用户旅程图的结构。用户旅程图通常展…...

【Vue3】知识汇总,附详细定义和源码详解,后续出微信小程序项目(2)

快速跳转&#xff1a; 我的个人博客主页&#x1f449;&#xff1a;Reuuse博客 新开专栏&#x1f449;&#xff1a;Vue3专栏 参考文献&#x1f449;&#xff1a;uniapp官网 ❀ 感谢支持&#xff01;☀ 前情提要 &#x1f53a;因为最近学习的vue语言&#xff0c;发现有很多细节…...

uniapp中使用全局样式文件引入的三种方式

如果你想在 uni-app 中全局引入 SCSS 文件&#xff08;例如 global.scss&#xff09;&#xff0c;可以通过以下步骤进行配置&#xff1a; 方法一&#xff1a;在 main.js 中引入 在 main.js 中引入全局样式&#xff1a; 你可以在 src/main.js 文件中直接引入 SCSS 文件&#xff…...

计算机网络易混淆知识点串记

文章目录 计算机网络易混淆知识点串记各层PDU首部: 计算机网络易混淆知识点串记 各层PDU首部: PUD首部长度 (B:字节)首部单位数据链路–帧帧首:14B帧尾部:4B——IPV420~60字节4B [通过4位二进制表示]IPV6固定首部40字节[可拓展]4BTCP20~60字节4BUDP8B字节...

Java代码审计-模板注入漏洞

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

如何在Linux中使用Cron定时执行SQL任务

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

数据集划分

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

带你读懂什么是AI Agent智能体

一、智能体的定义与特性 定义&#xff1a;智能体是一个使用大语言模型&#xff08;LLM&#xff09;来决定应用程序控制流的系统。然而&#xff0c;智能体的定义并不唯一&#xff0c;不同人有不同的看法。Langchain的创始人Harrison Chase从技术角度给出了定义&#xff0c;但更…...

react动态路由

在React应用中&#xff0c;动态路由&#xff08;Dynamic Routing&#xff09;通常指的是根据应用的状态或用户的交互来动态地显示或隐藏路由&#xff08;页面或组件&#xff09;。这可以通过多种方法实现&#xff0c;包括使用React Router库&#xff0c;它提供了强大的路由管理…...

Linux基础(十四)——BASH

BASH 1.BASH定义2.shell的种类3.bash的功能3.1 命令记录功能3.2 命令补全功能3.3 命令别名设置3.4 工作控制、 前景背景控制3.5 程序化脚本&#xff1a; &#xff08; shell scripts&#xff09;3.6 万用字符 4.bash的内置命令5.shell的变量功能5.1 变量的取用5.2 新建变量5.3 …...

架构师备考-概念背诵(系统架构)

软件架构概念 一个程序和计算系统软件体系结构是指系统的一个或者多个结构。结构中包括软件的构件,构件的外部可见属性以及它们之间的相互关系。体系结构并非可运行软件。确切地说,它是一种表达,使软件工程师能够: (1)分析设计在满足所规定的需求方面的有效性:(2)在设计变…...

如何让ffmpeg运行时从当前目录加载库,而不是从/lib64

程序在linux下运行时&#xff0c;一般从 /lib64 目录下加载依赖的库文件&#xff0c;如xxx.so. 有时候&#xff0c;系统里没有这些库&#xff0c;也不想从系统目录下加载&#xff0c;怎么办呢&#xff1f; 看下面的调整过程。 使用的源代码是 ffmpeg-6.1.tar.xz 解压后&…...

Kafka-Controller选举

一、上下文 《Kafka-broker粗粒度启动流程》博客中我们分析了broker的大致启动流程&#xff0c;这个时候每个broker都不是controller角色&#xff0c;下面我们就来看下它是如何选举出来的吧 二、设置ZooKeeper ‌ZooKeeper是一个开源的分布式协调服务&#xff0c;主要用于分…...

必知的 Vue3 组件传值技巧:解锁组件交互新姿势

父传子defineProps 基本概念 在 Vue 3 中&#xff0c;父传子是一种组件间通信的方式&#xff0c;用于将父组件的数据传递给子组件。这种通信方式可以让组件之间更好地协作&#xff0c;实现功能的复用和模块的划分。 实现步骤 在父组件中传递数据 App.vue <template>…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

7.4.分块查找

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

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

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

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...