此处以我所写的MAX7219为范例,从HDL接口描述到C语言软件编程,分析两种表面不一样、但实质是一样的寄存器映射方法,找出其中联系与区别。

方法1 使用Altera提供的API

1. 使用HDL描述Avalon-MM接口
代码1 Amy_S_max7219_avalon_interface.v
/*-----版权声明-----*     艾米电子工作室——让开发变得更简单 *     网站:http://www.amy-studio.com*     淘宝:http://amy-studio.taobao.com*     QQ(邮箱):amy-studio@qq.com*-----文件信息-----*     文件名称:Amy_S_max7219_avalon_interface.v*     最后修改日期:3.20, 2010*     描述:Max7219的Avalon接口描述文件*------------------*     创建者:张亚峰*     创建日期:3.20, 2009*     版本:1.0*     描述:原始版本*------------------*     修改者:*     修改日期:*     版本:*     描述:*-------------------*/module Amy_S_max7219_avalon_interface(// Clcok Inputinput         csi_clk,input         csi_reset_n,// Avalon-MM Slaveinput         avs_chipselect,input [1:0]   avs_address,input         avs_write,input [31:0]  avs_writedata,// Conduit End output reg    coe_din,output reg    coe_cs, output reg    coe_clk
);// write
always@(posedge csi_clk, negedge csi_reset_n)
beginif (!csi_reset_n)begin coe_din <= 1'b0;coe_cs  <= 1'b0;coe_clk <= 1'b0;    endelse if (avs_chipselect & avs_write)begincase (avs_address)0: coe_din <= avs_writedata[0];1: coe_cs  <= avs_writedata[0];2: coe_clk <= avs_writedata[0];endcaseend
endendmodule

<

;p>在这里,使用了3个寄存器,并通过avs_address来寻址。从50~52行,可以看出,这三个寄存器的偏移地址(Offset)分别是0、1和2。

2. 使用C语言编写寄存器映射文件
代码2 Amy_S_max7219.h 片段
//++++++++++++++++++++++++++++++++++++++
// 寄存器映射 开始
// 根据HDL编写
//++++++++++++++++++++++++++++++++++++++
#include #define IOWR_MAX7219_DIN(base, data)   IOWR(base, 0, data)
#define IOWR_MAX7219_CS(base, data)    IOWR(base, 1, data)
#define IOWR_MAX7219_CLK(base, data)   IOWR(base, 2, data)
//--------------------------------------
// 寄存器映射 结束
//--------------------------------------

注意:结尾那个</io.h>是发博客发出来的,不属于代码。

由于是使用ALtera的API——IOWR(),因此第5行,就得加上#include <io.h>。IOWR(base, offset, data)的3个输入参数,分别是IP的基地址,所使用寄存器的偏移地址,欲给所使用寄存器赋的值。寄存器的存储映射所使用的偏移地址,是有HDL中avs_address决定的。(avs avalon slave 阿窝龙从设备)

代码3 Amy_S_max7219.h 片段

代码描述:使用上面的已经映射好的函数

//++++++++++++++++++++++++++++++++++++++
// 基地址 开始
// 根据SOPC Builder设置编写
//++++++++++++++++++++++++++++++++++++++
#include "system.h"#define max7219_addr MAX7219_BASE
//--------------------------------------
// 基地址 结束
//--------------------------------------//++++++++++++++++++++++++++++++++++++++
// 寄存器映射 开始
// 根据HDL编写
//++++++++++++++++++++++++++++++++++++++
#include #define IOWR_MAX7219_DIN(base, data)   IOWR(base, 0, data)
#define IOWR_MAX7219_CS(base, data)    IOWR(base, 1, data)
#define IOWR_MAX7219_CLK(base, data)   IOWR(base, 2, data)
//--------------------------------------
// 寄存器映射 结束
//--------------------------------------//++++++++++++++++++++++++++++++++++++++
// 管脚操作 开始
//++++++++++++++++++++++++++++++++++++++
#define SET_DIN IOWR_MAX7219_DIN(max7219_addr, 1)
#define CLR_DIN IOWR_MAX7219_DIN(max7219_addr, 0)
#define SET_CS  IOWR_MAX7219_CS(max7219_addr, 1)
#define CLR_CS  IOWR_MAX7219_CS(max7219_addr, 0)
#define SET_CLK IOWR_MAX7219_CLK(max7219_addr, 1)
#define CLR_CLK IOWR_MAX7219_CLK(max7219_addr, 0)
//--------------------------------------
// 管脚操作 结束
//--------------------------------------

注意:结尾那个</io.h>是发博客发出来的,不属于代码

代码4 Amy_S_max7219.c代码片段

代码描述:使用Altera API的具体操作

#include "Amy_S_max7219.h"/** 发送一个字节的子程序:* 上升沿发送数据,* MSB first*/
void Max7219_WriteByte(alt_u8 byte)
{alt_u8 i;for (i=0; i<8; i++){CLR_CLK;if(byte & 0x80)SET_DIN;elseCLR_DIN;byte <<= 1;SET_CLK;}
}

至此,使用Altera的API来描述寄存器存储映射的方法,告一段落。

方法2 使用位域或结构体

其实这种方法,Altera的API的源代码有时也会用到。但是有一个地方需要注意,后面会提到。

1. 使用HDL描述Avalon-MM接口

如上。

2. 使用C语言编写寄存器映射文件
代码4 Amy_S_max7219.h 片段
//++++++++++++++++++++++++++++++++++++++
// 寄存器映射 开始
// 根据HDL编写
//++++++++++++++++++++++++++++++++++++++
#include "system.h"
#include "alt_types.h"typedef struct
{alt_u32 DIN : 32;alt_u32 CS  : 32;alt_u32 CLK : 32;
}MAX7219_T;#define m7219 ((MAX7219_T *)(MAX7219_BASE))
//--------------------------------------
// 寄存器映射 结束
//--------------------------------------

因为Nios II是32位的处理 器,所以之前定义了3个寄存器,都是32位的。此处为了表达这种关系,我们使用了位域。将这个位域(或结构体)重定义为一个类型,然后定义一个该类型的指针变量,起始地址是所需的基地址。这样做,就可以很好地为从基地址开始的连续的3x32位数据寻址(此处为3个寄存器,故数据总长3x32)。

代码5 Amy_S_max7219.c代码片段

代码描述:使用结构体指针寻址示例

/** 发送一个字节的子程序:* 上升沿发送数据,* MSB first*/
void Max7219_WriteByte(alt_u8 byte)
{alt_u8 i;for (i=0; i<8; i++){m7219->CLK = 0;if(byte & 0x80)m7219->DIN = 1;elsem7219->DIN = 0;byte <<= 1;m7219->CLK = 1;}
}

哈哈,是不是可以直接赋值了,更加像单片机了吧。其实Nios II就是单片机,32位的单片机。

做到这里,有些实验者在开发板上演练时,确实成功了;然而有些没有成功?这是为什么呢?我们先看参考资料1。

代码6 两种寄存器存储映射所对应的汇编
IOWR=32DIRECT(GPIO_LED_BASE, 0, 1);
0x04000234 : movhi r3,2048
0x04000238 : addi r3,r3,6144
0x0400023c : movi r2,1
0x04000240 : stwio r2,0(r3)LED = 1;
0x04000224 : movhi r3,2048
0x04000228 : addi r3,r3,6144
0x0400022c : movi r2,1
0x04000230 : stw r2,0(r3)

看到没有,两种寄存器存储映射所对应的汇编不一样。看关键字,一个是stwio,一个是stw。接下来打开手册,Table 3-36。

表1 宽数据传输指令

手册上清楚地写到,I/O外设的数据传输应该使用ldwio和stwio;这两条指令在传输时,是没有cache和buffer的。那怎样让结构体指针的寄存器映射方式也能使用ldwio和stwio呢。接着看手册,在98页,Cache Memory小节,写到 。那还有其他方法来实现cache bypass吗?第38页写到:

图1 Cache Bypass Method

图2 The Bit-31 Cache Bypass Method

好的,看代码。

代码7 system.h片段
#define ALT_MODULE_CLASS_max7219 Amy_S_max7219
#define MAX7219_BASE 0x1002020
#define MAX7219_IRQ -1
#define MAX7219_IRQ_INTERRUPT_CONTROLLER_ID -1
#define MAX7219_NAME "/dev/max7219"
#define MAX7219_SPAN 16
#define MAX7219_TYPE "Amy_S_max7219"

MAX7219_BASE=0x1002020,第31位是0;因此我们用结构体指针来寄存器存储映射时,传输的数据因数据缓存而出错。那我们就把这个Cache给Bypass(旁路)了。怎么办?把地址总线的第31位置一。

代码8 修改后的Amy_S_max7219.h片段
//++++++++++++++++++++++++++++++++++++++
// 寄存器映射 开始
// 根据HDL编写
//++++++++++++++++++++++++++++++++++++++
#include "system.h"
#include "alt_types.h"typedef struct
{alt_u32 DIN : 32;alt_u32 CS  : 32;alt_u32 CLK : 32;
}MAX7219_T;#define m7219 ((MAX7219_T *)(MAX7219_BASE | 1<<31))
//--------------------------------------
// 寄存器映射 结束
//--------------------------------------

在这里,我们直接通过或(1<<31)的方式,把第31位给置一了;这样从该基地址传输的数据就把数据缓存给旁路了;因为是I/O外设传输嘛。

好了,至此大功告成。我们可以自由切换喜欢的寄存器映射方式。

3. 一点其他内容

有时候我们所使用的寄存器并不一定都是32位的,这时要使用嵌套结构体来凑足32位,以防止寄存器寻址错误。

代码9 嵌套结构体示例
typedef struct{struct{alt_u8  DIN : 8;alt_u32 NC  : 24;}offset_0;  struct{alt_u8  CS  : 1;alt_u32 NC  : 31;}offset_1;  struct{alt_u8  CLK : 1;alt_u32 NC  : 31;}offset_2;
}MAX7219_T;

关于嵌套结构体,此处不解析,请读者自行分析。

对比

两种方法都不错,大家爱用什么就用什么。

参考

1. http://www.edaboard.com/ftopic354136.html

2. Altera.Nios II Processor Reference Handbook

http://www.altera.com/literature/hb/nios2/n2cpu_nii5v1.pdf

[笔记].浅析在Nios II中的两种寄存器映射方法的异同相关推荐

  1. (曲率系列3:)PCL:PCL库中的两种曲率表示方法pcl::NormalEstimation和PrincipalCurvaturesEstimation

    PCL里有两个计算曲率的调用函数: (1)pcl::NormalEstimation 这里边计算的曲率不是数学上定义的曲率. (2)pcl::PrincipalCurvaturesEstimation ...

  2. 【Vue】class style:Vue中的两种样式处理方法

    class属性 1.基本的class使用 <!DOCTYPE html> <html lang="en"> <head><meta cha ...

  3. [原创].怎样制作一个简单ip,以方便在Quartus II和Nios II中使用?

    概述:此处,我以Lcd12864(ST7920)作为范例,进行粗浅讲解,望各位网友踊跃拍砖.   0 软硬件环境 软件:Altera Quartus II 9.1 + Nios II  9.1 Sof ...

  4. [转载].怎样制作一个简单ip,以方便在Quartus II和Nios II中使用?

    1 硬件部分 1.1 Avalon-MM接口(读作:阿窝龙妹妹接口) Avalon Memory-Mapped接口,简称为 Avalon-MM接口,用于在存储映射系统中描述主从元件(component ...

  5. C语言学习笔记-----scanf【通过键盘将数据输入到变量中】(两种用法)

    C语言学习笔记-----scanf[通过键盘将数据输入到变量中](两种用法) 用法一:scanf("输入控制符",输入参数): 功能: 将从键盘输入的字符转化为输入控制符所规定格式 ...

  6. 深度学习中的两种不确定性:偶然不确定性和认知不确定性(Aleatoric Uncertainty Epistemic Uncertainty)

    转载:https://zhuanlan.zhihu.com/p/56986840 注: 本文中,概念.公式与实验均基于 Alex Kendall & Yarin Gal的论文:https:// ...

  7. 批量插入数据库语句java_java相关:MyBatis批量插入数据到Oracle数据库中的两种方式(实例代码)...

    java相关:MyBatis批量插入数据到Oracle数据库中的两种方式(实例代码) 发布于 2020-7-22| 复制链接 本文通过实例代码给大家分享了MyBatis批量插入数据到Oracle数据库 ...

  8. Cesium 中两种添加 model 方法的区别

    概述 Cesium 中包含两种添加 model 的方法,分别为: 通过 viewer.entities.add() 函数添加 通过 viewer.scene.primitives.add() 函数添加 ...

  9. java类型转换答案,在java中支持两种类型的类型转换,自动类型转换和强制类型转换。父类转化为子类需要强制转换。...

    在java中支持两种类型的类型转换,自动类型转换和强制类型转换.父类转化为子类需要强制转换. 更多相关问题 计算机病毒通过()传染扩散得极快,危害最大. 当一个现象的数量由小变大,另一个现象的数量相反 ...

最新文章

  1. VC6在64位Win7下调试无法退出的问题(缺少TLLOC.DLL和DM.dll)
  2. access 文本转换数字_ACCESS的短文本和长文本分类
  3. 一个迷失了本性的聊天软件,初衷不在,何其悲伤
  4. ubuntu 16.04安装redis群集zz
  5. php在类里如何调用call_user_func_array《细说php2》
  6. iOS C语言~bzero函数、memset函数
  7. 非常详细的Maven安装与配置教程
  8. 2.2 matlab矩阵变换(对角阵、三角阵、矩阵的转置、矩阵的旋转、矩阵的翻转和矩阵求逆)
  9. 菜鸡的求学之路-JavaScript
  10. LAMP 技术简介(2)
  11. 【论文整理】风格迁移中格拉姆矩阵(Gram Matrix)的使用
  12. Android 系统自带图片裁剪功能(适配7.0、8.0、对了还有小米手机)
  13. 洛谷P5072 [YNOI2015]盼君勿忘 莫队+unordered_set+毒瘤卡常
  14. perl对日志进行压缩备份小程序
  15. python_day6_面向对象的介绍/构造函数/类变量和实例变量/析构函数/私有属性和私有方法/继承、多继承和继承实例/多态
  16. CTF网络安全大赛介绍
  17. 2012年度十大杰出IT博客之 李云
  18. grid布局浏览器兼容_Grid布局
  19. [摘录]优势谈判简述
  20. SpringBoot 之 Tomcat 与 Undertow 容器性能对比

热门文章

  1. php增加vip等级设置,xiu主题添加vip等级评论样式
  2. 用python的turtle画正方形内切圆_Python 用turtle实现用正方形画圆的例子
  3. oracle 百万数据存储,jdbc oracle 百万级数据量存储
  4. let声明变量时的特点
  5. 未来教育计算机vb二级,2019年3月计算机二级VB考试巩固试题及答案020
  6. 订阅发布可靠吗_华辉人力资源可靠吗?发布的招聘信息是否可靠?
  7. linux查看某个端口的流量_Linux下如何对端口流量进行统计
  8. 南开计算机与控制工程学,2017南开大学计算机与控制工程学院考研复试名单
  9. 极光推送java服务器端_极光推送服务器端(JAVA)
  10. 深大计算机系有金工实习吗,金工实习报告答案深圳大学拿A答案(精选).pdf