一个简易的(不完整的)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. [随笔]CENTOS7更换YUM源为163源(记录一下以防忘记)

    2016年2月16日,最新163源变更后的更新方法: 访问地址为:http://mirrors.163.com/.help/centos.html 首先备份源: mv /etc/yum.repos.d ...

  2. RMAN备份(转)

    原文:http://blog.csdn.net/leshami/article/details/6032739 一.数据库备份与RMAN备份的概念 1.数据库完全备份:按归档模式分为归档和非归档 归档 ...

  3. python之CSV文件格式

    1.csv文件是以一些以逗号分隔的值 import csv filename = "wenjian.csv" with open(filename) as f: reader = ...

  4. document--文档中的操作,操作属性、操作样式、操作元素

    ---恢复内容开始--- document操作:    1.找元素   getE..    2.操作内容   非表单:innerHtml   表单:value    3.操作属性            ...

  5. Python之迭代器,生成器与装饰器

    1>迭代器原理及使用: 1>原理: 迭代器是访问集合元素的一种方式,迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束:迭代器只能往前不会后退,不过这也没什         ...

  6. VC中CDC与HDC的区别以及二者之间的转换

    CDC是MFC的DC的一个类 HDC是DC的句柄,API中的一个类似指针的数据类型. MFC类的前缀都是C开头的 H开头的大多数是句柄 这是为了助记,是编程读\写代码的好的习惯. CDC中所有MFC的 ...

  7. MongoDB 主从复制 的设置

    今天我们主要讨论mongodb的部署技术. 我们知道sql server能够做到读写分离,双机热备份和集群部署,当然mongodb也能做到,实际应用中我们不希望数据库采用单点部署, 如果碰到数据库宕机 ...

  8. SQL Server 2008R2 附件数据库问题记录

    在Sql Server 2008 R2里附加数据库时弹出xxx.mdf拒绝访问的错误 详细错误信息如下: TITLE: Microsoft SQL Server Management Studio-- ...

  9. WordCloud 简介

    WordCloud 简介 GitHub GitHub:https://github.com/amueller/word_cloud example:https://github.com/amuelle ...

  10. 小修改,让mvc的验证锦上添点花(2)

    上一篇文章我们演示了通过对jquery.validate.unobtrusive.js做点小修改,如何给MVC的验证添点花 主要还是修改了onError与onSuccess中的这两个方法 这两个方法也 ...