一个简易的(不完整的)APB4 slave的可以没有PREADY和PSLVERR,这两个信号都被赋予常数,以及没有PPROT。

两种不同类型的寄存器:

图: 普通寄存器电路图

图: 带读写控制寄存器电路图

图:带读写控制寄存器时序图

一般来讲,一个模块的interface到内部reg之间,需要的信号为地址信号addr,读写使能信号(分开),byte_strobe字节选通信号,读写数据信号(分开)。

注意:在传输结束后不要立即更改地址和写信号,保持当前状态知道开始下一个传输,这样可以降低功耗。

interface spec:

寄存器表:

代码:apb4的顶层

 module apb4_slave #(
parameter ADDRWIDTH = )
(
input wire       PCLK,
input wire       PRESETn, input wire PSEL,
input wire[ADDRWIDTH -:] PADDR,
input wire PENABLE,
input wire PWRITE,
input wire[:] PWDATA,
input wire[:] PSTRB, input wire[:] ECOREVNUM, output wire[:] PRDATA,
output wire PREADY,
output wire PSLVERR
);
  wire  [ADDRWIDTH-:]  reg_addr;
  wire             reg_read_en;
  wire             reg_write_en;
  wire  [:]        reg_byte_strobe;
  wire  [:]        reg_wdata;
  wire   [:]        reg_rdata;
apb4_slave #(.ADDRWIDTH  (ADDRWIDTH))
  u_apb_slave_interface(
.pclk        (PCLK),
.presetn      (PRESETn), .psel        (PSEL),
.paddr       (PADDR),
.penable      (PENABLE),
.pwrite       (PWRITE),
.pwdata       (PWDATA),
.pstrb       (PSTRB), .prdata       (PRDATA),
.pready       (PREADY),
.pslverr      (PSLVERR), .addr        (reg_addr),
.read_en       (reg_read_en),
.write_en      (reg_write_en),
.byte_strobe    (reg_byte_strobe),
.wdata        (reg_wdata),
.tdata        (reg_rdata) );

 如何在interface这个模块中确定APB的建立周期信号?

其实APB的建立周期信号可以理解为一个使能信号,在第一周期拉高这个使能信号,那么下个周期就可以判断使能信号,并进入到传输周期了。这里使用组合逻辑去解决使能信号问题,一个是读使能read_en,一个是写使能write_en。read_en = psel &(~pwrite); write_en = psel &(~penable) & pwrite;  这里peanble是主机发过来的输入信号,这里说的从机不用管。

代码:apb4的逻辑接口

u_apb_slave_interfacef #(
parameter ADDRWIDTH = )
(
// IO declaration
input wire pclk,
input wire presetn,
// apb interface input
input wire psel,
input wire[ADDRWIDTH-:] paddr,
input wire penable,
input wire pwite,
input wire[:] pwdata,
input wire[:] pstrb,
// apb interface output
output wire[:] prdata,
output wire pready,
// Register interface
output wire[ADDRWIDTH-:] addr,
output wire read_en,
output wire write_en,
output wire[:] byte_pstrb,
output wire[:] wdata,
output wire[:] rdata
); assign pready = 'b1;
assign pslverr = 'b0; assign addr = paddr;
assign read_en = psel & (~pwrite); // 当pwrite为0,psel为1的时候,才读
assign write_en = psel & (~penable) & pwrite; // 在PCLK中,第一拍为psel有效,penable为低,第二拍才是psel和penable同时有效; assign byte_pstrb = pstrb;
assign wdata = pwdata;
assign prdata = rdata;

 如何设计有等待状态的写传输?

从模块的pready输出之前一直是高,现在想延迟一个时钟周期,做成脉冲形式。

可以使用组合逻辑如:

assgin pready_1 = psel & peanble & pwrite;

pready想延迟多个时钟节拍,可以使用时序电路,建立周期完成后,等待多个clock之后,再讲pready拉高。

代码:apb的寄存器读写

module apb4_slave_reg #(
parameter ADDRWIDTH = )
(
input wire pclk,
input wire presetn, input wire[ADDRWIDTH-:] addr,
input wire read_en,
input wire write_en,
input wire[:] byte_pstrb,
input wire[:] wdata,
input wire ecorevnum,
output wire[:] rdata ); localparam ARM_CMSDK_APB4_EG_SLAVE_PID4 = 'h00000004; // 12'hFD0;
localparam ARM_CMSDK_APB4_EG_SLAVE_PID5 = 'h00000000; // 12'hFD4;
localparam ARM_CMSDK_APB4_EG_SLAVE_PID6 = 'h00000000; // 12'hFD8;
localparam ARM_CMSDK_APB4_EG_SLAVE_PID7 = 'h00000000; // 12'hFDC;
localparam ARM_CMSDK_APB4_EG_SLAVE_PID0 = 'h00000019; // 12'hFE0;
localparam ARM_CMSDK_APB4_EG_SLAVE_PID1 = 'h000000B8; // 12'hFE4;
localparam ARM_CMSDK_APB4_EG_SLAVE_PID2 = 'h0000001B; // 12'hFE8;
localparam ARM_CMSDK_APB4_EG_SLAVE_PID3 = 'h00000000; // 12'hFEC; wire [:] wr_sel; // 取地址的高10位出来,地址是4K对其的,之后高12bits是不一样的,从0xfff~0x000,其中的高10位就可以判断出是要操作那个寄存器了
// 地址是32为对其的,末尾都是0(0000)、4(0100)、8(1000)、C(1100)循环的,低两位都是一样的,只有高10位不一样
assign wr_sel[] = ((addr[(ADDRWIDTH-):]=='b0000000000)&(write_en)) ? 1'b1: 'b0;
assign wr_sel[] = ((addr[(ADDRWIDTH-):]=='b0000000001)&(write_en)) ? 1'b1: 'b0;
assign wr_sel[] = ((addr[(ADDRWIDTH-):]=='b0000000010)&(write_en)) ? 1'b1: 'b0;
assign wr_sel[] = ((addr[(ADDRWIDTH-):]=='b0000000011)&(write_en)) ? 1'b1: 'b0; // write_en = psel & (~penable) & pwrite; 时序要求在penable为高这一拍把数据写下去,所以要在其前一拍判断是否要写。 // 寄存器的写操作
// Data register: data0
always @(posedge pclk or negedge presetn) begin
if (~presetn) begin
data0 <= {{'b0}};
end
else if (wr_sel[]) begin
if (byte_strobe[])
data0[ :] <= wdata[:];
if (byte_strobe[])
data0[:] <= wdata[:];
if (byte_strobe[])
data0[:] <= wdata[:];
if (byte_strobe[])
data0[:] <= wdata[:];
end
end
// Data register: data1
always @(posedge pclk or negedge presetn) begin
if (~presetn) begin
data1 <= {{'b0}};
end
else if (wr_sel[]) begin
if (byte_strobe[])
data1[ :] <= wdata[:];
if (byte_strobe[])
data1[:] <= wdata[:];
if (byte_strobe[])
data1[:] <= wdata[:];
if (byte_strobe[])
data1[:] <= wdata[:];
end
end
// Data register: data2
always @(posedge pclk or negedge presetn) begin
if (~presetn) begin
data2 <= {{'b0}};
end
else if (wr_sel[]) begin
if (byte_strobe[])
data2[ :] <= wdata[:];
if (byte_strobe[])
data2[:] <= wdata[:];
if (byte_strobe[])
data2[:] <= wdata[:];
if (byte_strobe[])
data2[:] <= wdata[:];
end
end
// Data register: data3
always @(posedge pclk or negedge presetn) begin
if (~presetn) begin
data3 <= {{'b0}};
end
else if (wr_sel[]) begin
if (byte_strobe[])
data3[ :] <= wdata[:];
if (byte_strobe[])
data3[:] <= wdata[:];
if (byte_strobe[])
data3[:] <= wdata[:];
if (byte_strobe[])
data3[:] <= wdata[:];
end
end // 寄存器的读操作
always @(read_en or addr or data0 or data1 or data2 or data3 or ecorevnum) begin
case (read_en)
'b1: begin
if (addr[:] == 'h00) begin // 判断为RW类型的寄存器
case (addr[:])
'b00: rdata = data0;
'b01: rdata = data1;
'b10: rdata = data2;
'b11: rdata = data3;
default: rdata = {{'bx}};
endcase
end
else if (addr[:] == 'h3F) begin // 判断为RO类型的寄存器
case(addr[:])
'b0100:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID4;
'b0101:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID5;
'b0110:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID6;
'b0111:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID7;
'b1000:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID0;
'b1001:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID1;
'b1010:rdata = ARM_CMSDK_APB4_EG_SLAVE_PID2;
'b1011:rdata = {ARM_CMSDK_APB4_EG_SLAVE_PID3[31:0],ecorevnum[3:0],4'h0};
default: rdata = {{'bx}};
endcase
end
else begin
rdata = {{'b0}};
end
end
'b0: begin
rdata = {{'b0}};
end
default: rdata = {{'bx}};
endcase
end endmodule

简易APB4 slave实践的更多相关文章

  1. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

  2. Redis Master/Slave 实践

    本次我们将模拟 Master(1) + Slave(4) 的场景,并通过ASP.NET WEB API进行数据的提交及查询,监控 Redis Master/Slave 数据分发情况,只大致概述,不会按 ...

  3. proto3 不支持内建类型的非空判断即 hasXXX

    proto3 移除了内建类型的非空判断方法 即代码生成工具不会为 bool int 等类型生成has方法 有使用过proto2 或者其它rpc 框架的人都知道使用has 方法去判断消息里的值是否设置, ...

  4. Vue2.0 + Element-UI + WebAPI实践:简易个人记账系统

    最近正在学习Vue2.0相关知识,正好近期饿了么桌面端组件Element-UI发布,便动手做了一款简易个人记账系统,以达到实践及巩固目的. 1.开发环境 Win10 + VS2015 + Sqlser ...

  5. 【原创 Hadoop&Spark 动手实践 13】Spark综合案例:简易电影推荐系统

    [原创 Hadoop&Spark 动手实践 13]Spark综合案例:简易电影推荐系统

  6. docker简易实践

    docker简易实践 实验环境 操作系统:deepin 15.4 安装步骤 1.安装docker sudo apt-get install docker.io 2.启动docker服务 sudo se ...

  7. 基于OVS的VLAN虚拟化简易实践方案

    基于OVS的VLAN虚拟化简易实践方案 前言 本实验基于ovs的vlan流表匹配,根据端口进行vlan标签插入.手工配置ovs,使其具有vlan虚拟化方案. 实验拓扑 ---- ---- | h1 | ...

  8. 《Java 程序设计》课堂实践项目-简易计算器

    <Java 程序设计>课堂实践项目简易计算器 课后学习总结 目录 改变 简易计算器实验要求 课堂实践成果 课后思考 改变 修改了博客整体布局,过去就贴个代码贴个图很草率,这次布局和内容都有 ...

  9. c++开发ocx入门实践三--基于opencv的简易视频播发器ocx

    原文:http://blog.csdn.net/yhhyhhyhhyhh/article/details/51404649  利用opencv做了个简易的视频播放器的ocx,可以在c++/c#/web ...

随机推荐

  1. [SoapUI] SoapUI可以做到些什么?功能有多强大?

    SoapUI. The Swiss-Army Knife of Testing. Whether you’re a tester, developer, business analyst, or ma ...

  2. sed命令n,N,d,D,p,P,h,H,g,G,x解析2

    摘自: https://blog.csdn.net/xiexingshishu/article/details/50514132 sed命令n,N,d,D,p,P,h,H,g,G,x解析 2016年0 ...

  3. log4j-over-slf4j工作原理详解

    log4j-over-slf4j工作原理详解 摘自:https://blog.csdn.net/john1337/article/details/76152906 置顶 2017年07月26日 17: ...

  4. Scala入门学习随笔

    推荐学习视频:慕课网http://www.imooc.com/learn/613,讲师:辰风 ScalaAPI:http://www.scala-lang.org/api/current/#packa ...

  5. [GO]匿名函数和defer

    package main import "fmt" func main() { a := 10 b := 20 defer func() { fmt.Printf("a ...

  6. STL之erase用法

    vector::erase():从指定容器删除指定位置的元素或某段范围内的元素 vector::erase()方法有两种重载形式 如下: 1.iterator erase(iterator _Wher ...

  7. query.validate.js使用说明+中文API

    转自:http://www.cnblogs.com/hejunrex/archive/2011/11/17/2252193.html 看到一篇好的文章不容易,记录下来以防丢失! 官网地址:http:/ ...

  8. 如何快速增加pdf书签,解除pdf限制

    一.需要的工具 福昕PDF阅读器 Foxit PDF Editor 2.2.1 build 1119 汉化版 下载地址:http://www.onlinedown.net/soft/51002.htm ...

  9. HALCON机器视觉软件

    HALCON是德国MVtec公司开发的一套完善的标准的机器视觉算法包,拥有应用广泛的机器视觉集成开发环境.它节约了产品成本,缩短了软件开发周期——HALCON灵活的架构便于机器视觉,医学图像和图像分析 ...

  10. How To Start Building Spatially Aware Apps With Google’s Project Tango

    How To Start Building Spatially Aware Apps With Google’s Project Tango “Tango can enable a whole new ...