目录

  • 1. HTRANS没法用
  • 2. IDLE
  • 3. 写
  • 4. 读
  • 5. 代码

AHB协议毕竟与FIFO、RAM等读写协议不一样,而AHB是SoC系统片内常用的高速接口,所以就需要将AHB的时序转化为标准的握手时序,例如下图

本文介绍整个设计的逻辑


从上图可以看出,AHB2HANDSHAKE模块是作为AHB slave出现的,所以要从AHB Slave角度进行设计。

依然是按照状态机的思路。如果是状态机的思路,AHB协议中HTRANS有四种状态、HBURST有八种状态,我们使用哪一个呢?还是自己写状态机?

可选择思路是基于HTRANS的IDLE、BUSY、NONSEQ和SEQ四种状态进行设计,毕竟burst传输属于NONSEQ或SEQ状态。

1. HTRANS没法用

哈哈哈我根据HTRANS的四种状态设计了半天发现作为AHB slave压根就没法用状态机。

先看看下面这几张波形图,从AHB Slave的角度思考一下

上图中揭示了AHB比较膈应的地方,就是一次访问地址和数据是分两拍进行的,当然这也是实现流水的基础。这就导致了第二拍传数据的时候,地址可以发生变化。

所以如果对一个地址的访问需要两拍,注意这两拍中address phase与data phase可不在同一个HTRANS,data phase甚至会跨越多个HTRANS状态。

换句话说就是,HTRANS这个状态机不能决定hwdata和hrdata信号的变化规律。
这个与平时的状态机设计不同,平时设计的思路是整个模块被分成好几个状态,该模块的每个信号会根据不同状态变化规律不一。
但是AHB协议中HADDR会根据HTRANS的取值来决定是否有效,而HWDATA和HRDATA的变化并不会参照HTRANS这个状态。

但是作为AHB Slave不必关心有没有跨HTRANS、HTRANS某个状态是否要延迟,这个是AHB Master要做的事情。作为slave,只需要将数据正确写入或正确读出即可

那么如何对AHB到标准握手时序桥进行设计呢?还是状态机,不过我们采用最原始的状态机:

2. IDLE

该状态下当然是啥都不干啦,当检测到AHB master要进行传输时,即htrans为NONSEQ时,检测hwrite判断转入WRITE还是READ,如下图

于是状态机重写为

3. 写

该状态下实现写,当标准握手时序下写完成该状态结束。

注意是标准握手时序,所以需要将地址和数据在时序上对齐。

怎么实现呢?时序图在IDLE已经展现了,如下图带反压的WRITE

即便是burst写也可以

而WRITE下一个状态,则根据WRITE结束的那一拍htrans的值,状态机如下

关于那个BUSY作一下说明。AHB master在进入BUSY时会给出下一个传输的控制信号,但是在下一次传输真正来临时控制信号还会保持不变,所以在AHB slave检测到wr_en && hready && (htrans == BUSY)时依旧可以转换为IDLE状态

4. 读

该状态下实现读,当确定读出数据了该状态结束。

同样要求rd_en与rdata时序对齐,如果与写类似,将haddr打拍成raddr,那么在data phase第一拍必然不会读出数据,最快也要第二拍。

也就是说,必然会反压一拍,如下图带延迟的情况。

由此状态机更新为

5. 代码

module ahb2standard_handshake_bridge#(parameter  HADDR_WIDTH = 32,parameter HDATA_WIDTH = 32parameter  ACCESS_ADDR1 = 32'h0000_0000_0000_0010,parameter  ACCESS_ADDR2 = 32'h0000_0000_0000_0014,parameter  ACCESS_ADDR3 = 32'h0000_0000_0000_0018,parameter  ACCESS_ADDR4 = 32'h0000_0000_0000_001C)(input                         hrstn,input                         hclk,input  [HADDR_WIDTH-1:0]   haddr,input [2:0]               hburst,input    [2:0]               hsize,input [1:0]               htrans,input                        hwrite,input                        hsel,input  [HDATA_WIDTH-1:0]   hwdata,output   [HDATA_WIDTH-1:0]   hrdata,output                       hready,output                       hresp,output    [HADDR_WIDTH-1:0]   waddr,output    [HDATA_WIDTH-1:0]   wdata,output                        wr_en,input                     wready,output   [HADDR_WIDTH-1:0]   raddr,input [HDATA_WIDTH-1:0]   rdata,input                     rdata_val,output                        rd_en,input                     rready);localparam      IDLE = 2'b00;
localparam      WRITE = 2'b01;
localparam      READ = 2'b11;reg      [1:0]               cur_state;
reg     [1:0]               nxt_state;
reg     [HADDR_WIDTH-1:0]   waddr_r;
reg     [HADDR_WIDTH-1:0]   raddr_r;
reg                         hready_r;
reg                         wr_en_r;
reg                         rd_en_r;
reg                         hresp_r;always@(posedge hclk or negedge hrstn) beginif(!hrstn)cur_state <= IDLE;elsecur_state <= nxt_state;
endalways@(*) begincase(cur_state)IDLE:if(htrans[1]) beginif(hwrite)nxt_state = WRITE;elsenxt_state = READ;endelsenxt_state = IDLE;WRITE:if(wr_en && hready) beginif(!htrans[1])nxt_state = IDLE;else if(!hwrite)nxt_state = READ;elsenxt_state = WRITE;endelsenxt_state = WRITE;READ:if(rdata_val) beginif(!htrans[1])nxt_state = IDLE;else if(hwrite)nxt_state = WRITE;elsenxt_state = READ;endelsenxt_state = READ;default:nxt_state = IDLE;endcase
endassign wdata = hwdata[(8 << hsize)-1:0];always@(*) begincase(cur_state)IDLE:hready_r = 1'b0;WRITE:hready_r = wready;READ:hready_r = rdata_val;default:hready_r = 1'b0;endcase
endassign hready = hready_r;always@(posedge hclk or negedge hrstn) beginif(!hrstn)waddr_r <= 'd0;else if(cur_state == IDLE) beginif(htrans[1] && hwrite)waddr_r <= haddr;endelse if(cur_state == WRITE) beginif(wr_en && hready && htrans[1] && hwrite)waddr_r <= haddr;endelse if(cur_state == READ) beginif(rdata_val && htrans[1] && hwrite)waddr_r <= haddr;end
endassign waddr = waddr_r;always@(posedge hclk or negedge hrstn) beginif(!hrstn)wr_en_r <= 1'b0;else if(cur_state == IDLE) beginif(htrans[1] && hwrite)wr_en_r <= 1'b1;endelse if(cur_state == WRITE) beginif(!hready)wr_en_r <= wr_en_r;else if(htrans[1]) beginif(hwrite)wr_en_r <= 1'b1;elsewr_en_r <= 1'b0;endelsewr_en_r <= 1'b0;endelse if(cur_state == READ) beginif(rdata_val && htrans[1] && hwrite)wr_en_r <= 1'b1;end
endassign wr_en = wr_en_r;assign hrdata = rdata[(8 << hsize)-1:0];always@(posedge hclk or negedge hrstn) beginif(!hrstn)raddr_r <= 'd0;else if(cur_state == IDLE) beginif(htrans[1] && !hwrite)raddr_r <= haddr;endelse if(cur_state == WRITE) beginif(wr_en && hready && htrans[1] && !hwrite)raddr_r <= haddr;endelse if(cur_state == READ) beginif(rdata_val && htrans[1] && !hwrite)raddr_r <= haddr;end
endassign raddr = raddr_r;always@(posedge hclk or negedge hrstn) beginif(!hrstn)rd_en_r <= 1'b0;else if(cur_state == IDLE) beginif(htrans[1] && !hwrite)rd_en_r <= 1'b1;endelse if(cur_state == WRITE) beginif(wr_en && hready && htrans[1] && !hwrite)rd_en_r <= 1'b1;endelse if(cur_state == READ) beginif(!rready)rd_en_r <= rd_en_r;else if(!rdata_val)rd_en_r <= 1'b0;else if(htrans[1]) beginif(hwrite)rd_en_r <= 1'b0;elserd_en_r <= 1'b1;endelserd_en_r <= 1'b0;endelse rd_en_r <= 1'b0;
endassign rd_en = rd_en_r;always@(*) beginif(cur_state == WRITE && wr_en && hready) beginif(waddr != ACCESS_ADDR1 && waddr != ACCESS_ADDR2&& waddr != ACCESS_ADDR3&& waddr != ACCESS_ADDR4)hresp_r = 1'b1;endelse if(cur_state == READ && rdata_val) beginif(raddr != ACCESS_ADDR1 && raddr != ACCESS_ADDR2&& raddr != ACCESS_ADDR3&& raddr != ACCESS_ADDR4)hresp_r = 1'b1;endelsehresp_r = 1'b0;
endassign hresp = hresp_r;endmodule

AHB到标准握手时序桥 - 逻辑设计部分相关推荐

  1. 手机APP开发之MIT Appinventor详细实战教程(十),标准登陆界面的逻辑设计和数据库的有效使用

    目录 (一)APP功能介绍 (二)设计流程 (三)知识点 (四)问题 (五)总结 (一)APP功能介绍 今天我们来学习设计一个登录界面的APP,虽然界面有些简陋,但其内在的逻辑设计却并不简单.我们首先 ...

  2. 串行外设接口(Serial Peripheral Interface, SPI)逻辑设计部分 - spi_master

    目录 1. baud_clk_gen 1.1. 代码 2. spi_master 2.1. IDLE:等待写入 2.2. WAIT_CS:等待选通 2.3. TRANS:传输 (CPOL ^ CPHA ...

  3. UART的RTL逻辑设计部分 - uart_tx

    目录 1. IDLE:等待并数据到来 1.1. valid&ready 的Slave写握手 1.2. 异步FIFO 的Master读握手 2. TRANS:并串转换 2.1. 打包tx_dat ...

  4. FPGA逻辑设计回顾(10)DDR/DDR2/DDR3中的时序参数的含义

    前言 本文首发自:FPGA逻辑设计回顾(10)DDR/DDR2/DDR3中的时序参数的含义 上篇文章:FPGA逻辑设计回顾(9)DDR的前世今生以及演变过程中的技术差异有提到,制造商会以一系列由破折号 ...

  5. 数字逻辑基础实验二—时序逻辑电路的设计

    实验目的 (1)掌握中规模集成寄存器构成的时序逻辑电路的设计方法. (2)掌握中规模集成计数器设计N进制计数器的方法. (3)学会用时序功能器件构成综合型应用电路. 实验电路 图 2-1红绿灯电路 实 ...

  6. 计算机逻辑模块,常用时序逻辑电路模块 《计算机结构与 及逻辑设计》课件.ppt...

    常用时序逻辑电路模块 <计算机结构与 及逻辑设计>课件.ppt * ② 用反馈清0法实现模6计数 Q3Q2Q1Q0 & 0000 0001 0010 0011 0100 0101 ...

  7. FPGA逻辑设计回顾(8)单比特信号的CDC处理方式之Toggle同步器

    文章目录 前言 脉冲反馈展宽同步器技术补充说明 RTL代码 行为仿真 低电平脉冲的展宽处理 切换同步器的原理与实现 RTL实现 前言 本文首发自:FPGA逻辑设计回顾(8)单比特信号的CDC处理方式之 ...

  8. 数字逻辑计算机组成,数字逻辑设计与计算机组成pdf

    数字逻辑设计与计算机组成 内容简介 本书从简单的数字逻辑电路设计基础开始,由浅入深,讲解组合逻辑和时序逻辑电路的设计技术.计算机组成的基本原理和计算机体系结构的相关概念,后深入探讨了现代计算机系统如何 ...

  9. 数字电路逻辑设计笔记(2):逻辑代数基础

    数字电路逻辑设计笔记(2):逻辑代数基础 参考教材:<数字电路逻辑设计>欧阳星明 人民邮电出版社 参考教程: 中国大学MOOC 西安工业大学<数字电子技术基础> 文章目录 数字 ...

最新文章

  1. 英特尔:谁说深度学习已死?AI任务挑大梁的是CPU,不是GPU
  2. 手机影音第六天 自定义播放器页面的实现(按钮暂时未监听)
  3. 中断(interrupted()、isInterrupted())、Executor的中断
  4. Table.Rows.Remove(dr)和Table.Delete()的区别
  5. 【定时同步系列4】QPSK调制+OM定时(FFT实现及频域补偿)+信号分段处理+误码率曲线之MATLAB仿真(复信号模型)
  6. RocksDB事务实现TransactionDB分析
  7. 研讨会 | 知识工程与问答技术研讨会 (KEQA2018)
  8. windows功能_这 12 个好用 Windows 软件,让你也能用上 macOS 的独占功能
  9. 实时“头发-面部皮肤”分割与人脸肤色分类
  10. 轻量级日志系统Loki原理简介和使用
  11. 3.2 Lucene实战:一个简单的小程序
  12. .Net免费公开课视频+资料+源码+经典牛逼 汇总篇【持续更新】
  13. 【图像去噪】基于matlab GUI多种滤波器图像去噪【含Matlab源码 1778期】
  14. moodle重定向_用最简单的pythonGUI库PysimpleGUI 设计一款中丹学院Moodle课件下载器。...
  15. android自定义popwindow,Android应用开发Android 自定义PopWindow的简单使用
  16. struts2之拦截器详解
  17. syntax sugar 2
  18. 一步一步教你写股票走势图——分时图五(自定义标记)
  19. Seventh season fifteenth episode,Joey got a new brain??????
  20. 转不撞南墙不回头——树规总结

热门文章

  1. 城市园区NB-IoT智慧井盖解决方案
  2. 第二百四十一节,Bootstrap进度条媒体对象和 Well 组件
  3. 华为机试HJ16:购物单
  4. ubuntu怎么设置系统语言英文_Ubuntu系统设置中文语言的方法教程,Ubuntu系统怎么设置中文语言?...
  5. 虚拟主机的构建——基于域名、端口、IP
  6. idea使用小技巧(一)
  7. shell基础(2):编程基础之变量:全局/局部/环境变量(作用域、定义、操作)、位置参数、数组
  8. Vue渲染Leaflet GIS地图,边界线,点位组件
  9. 钉钉中添加回调监听事件
  10. 西门子RS485通信笔记