Verilog自制NIOS2外设,Avalon总线上的HelloWorld
虚无的目录
- 嘿嘿嘿,开新坑
- 这个时候有个CPU来测试就太好了
- 总线
- 这次只用到下面几个必要的信号
- 接下来干什么
- 自制外设的代码
- Qsys配置新组件
- 连接到Nios内核
- 配置顶层连接
- 来吧,eclipse
- 没用?这就对了
- 内存一致性问题
- 新姿势以后接着讲
嘿嘿嘿,开新坑
一开始想写一个SDRAM
控制器,和FTDI
一些芯片的通信,可是看了很多文章介绍,用Verilog写却又不知如何下手。SDRAM
控制部分知道了,控制器是用来读写的,总得有个内部接口来调用吧。有很多的FPGA设计也是一样,我设计出来了怎么知道他是可以用的呢?我总不能使用几个LED和数码管来表示吧?写状态机来测试的话可能比设计电路的本身更复杂更枯燥。
这个时候有个CPU来测试就太好了
Nios2是Altera的32bit哈弗架构软核处理器,在Cyclone IV
上一个基本内核综合后占了4.5K
左右的资源,剩下的资源相对来说还是很充足的。Nios2各方面的资料支持很足,设计也很标准,各种完善的IP核,C语言开发环境也是自带的,自动化的工具应有尽有,生怕你不会用。完全没有必要为此而自制一个CPU,大费周折,我们的主要矛盾不是自制CPU,也不是自制总线协议,而是一个足够简单的总线和总线主机:CPU。一些IP核学习自己写才是目标。
总线
说起总线我就想起了,今年下半年学习的微机原理与接口技术,8086/8088
。这套总线足够简单嘛都是,那个时候才分清了总线和IO,CPU和外设的关系。学单片机配置的各种寄存器的不都是挂在总线上可以寻址的外设嘛! x86
就是特殊搞了个I/O
总线,用in
,out
指令访问,Nios和ARM Cortex-M单片机差不多嘛,都是和内存统一寻址。Nios2用的是Avalon总线,名字莫名其妙,其实这个总线非常简单。
这次只用到下面几个必要的信号
clock(1bit)
时钟信号,8086的总线不是靠时钟边沿,而是靠等待一个总线周期resetn(1bit)
下降沿复位信号writedata(16bit)
写数据readdata(16bit)
读数据read(1bit)
读信号write(1bit)
写信号byteenable(2bit)
字节使能信号chipselect(1bit)
片选信号
address
地址是可选的,根据自己定制的寄存器数量而定,只有一个的话chipselect
选中外设就可以了。irq
中断请求不需要,放在以后的文章里面讲。
8086中的data
数据线是双向的为的是节省IO,FPGA里面的总线用inout
做双向端口的话只会更浪费资源,设计起来也会复杂,所以readdata和writedata分开了。
byteenable
看起来很奇怪,32bit的总线有的时候难免操作1个byte的数据,bytenenable
是告诉外设要操作哪一byte数据。byteenable
的位宽和writedata
的位宽是相关的,如果writedata
的位宽为32bit,byteenable
就应该是4bit。注意:'byteenable’只对写操作有效。
byteenable[1:0] | write mask |
---|---|
01 |
0x00ff
|
10 |
0xff00
|
11 |
0xffff
|
接下来干什么
接下来做一个16bit寄存器,写进去的数据读出来是取过反的,实验一个所谓的硬件取反。为了方便我们把它接到低电平驱动的一排LED上,方便观察。
自制外设的代码
// 16位寄存器
module reg16(clock, reset_n, D, byteenable, Q);input clock, reset_n;input [1:0]byteenable;input [15:0]D;output reg[15:0]Q;always@(posedge clock) beginif(!reset_n)Q <= 16'h0;else begin// byteenable只是判断哪个字节是否锁存if(byteenable[0]) Q[7:0] <= D[7:0];if(byteenable[1]) Q[15:8] <= D[15:8];endend
endmodulemodule LEDS(// Inputclk,reset_n,// address,byteenable,read,write,writedata,chipselect,// Outputreaddata,Q_export
);input clk, reset_n, read, write, chipselect;// input address;
input [1:0]byteenable;
input [15:0]writedata;
output [15:0] readdata;
output [15:0] Q_export;wire [1:0] local_byteenable;
wire [15:0]from_reg;// 片选且写入,否则的话local_byteenable为0,不改变寄存器值
assign local_byteenable = (chipselect & write) ? byteenable: 2'b00;reg16 U1(.clock(clk), .reset_n(reset_n), .D(writedata), .byteenable(local_byteenable), .Q(from_reg));// 取反输出
assign Q_export = ~from_reg;
assign readdata = Q_export;
endmodule
Qsys配置新组件
配置一个基本的Nios有很多,就不在此举出了。
- Qsys配置新组件,随便起个名字
- 选择文件,和顶层入口
- 信号设置
设置后的信号如上图,需要设计的也就Q_export,设置为conduit_end
导出IO。 interface
设置需要两步
- Avalon slave复位关联信号
- 设置
Read wait
为0, 内部寄存器的读取只需要1个时钟周期, 不需要等待
连接到Nios内核
- 地址自动分配
- 复位信号自动连接
- 从机只需要连接数据总线
data master
condiuit_end
就是设置导出的信号,双击设置导出名称,导出到一组LED观察
配置顶层连接
module hello
(input clk,input[3:0] key,inout[15:0] sdram_dq,output[12:0] sdram_addr,output[1:0] sdram_dqm,output sdram_we_n,output sdram_cas_n,output sdram_ras_n,output sdram_cs_n,output[1:0] sdram_ba,output sdram_clk,output sdram_cke,input epcs_data0,output epcs_dclk,output epcs_sce,output epcs_sdo,output[3:0] leds
);
wire clk_qsys;
pll pll_inst
(.inclk0 (clk),.c0 (clk_qsys),.c1 (sdram_clk)
);
qsys qsys_inst
(.clk_clk (clk_qsys), .reset_reset_n (key[3]),.sdram_addr (sdram_addr),.sdram_ba (sdram_ba),.sdram_cas_n (sdram_cas_n),.sdram_cke (sdram_cke), .sdram_cs_n (sdram_cs_n),.sdram_dq (sdram_dq),.sdram_dqm (sdram_dqm), .sdram_ras_n (sdram_ras_n),.sdram_we_n (sdram_we_n),.epcs_data0 (epcs_data0), .epcs_dclk (epcs_dclk),.epcs_sce (epcs_sce),.epcs_sdo (epcs_sdo),.to_led_export (leds)
);
endmodule
太寒碜了,板子只有4个LED,能看就行,按理说,低电平亮的LED,寄存器写1取反后就亮了。记得锁相环给CPU一个时钟。
来吧,eclipse
打开Nios II开发环境,配置一个Hello World
的C工程。很多文章有讲,就不多说了。记得BSP更新生成库文件。
#include <stdio.h>
#include <stdint.h>
#include "system.h"
#include "io.h"typedef struct {uint16_t led;
} LEDS;int main()
{printf("Hello from Nios II!\n");LEDS *leds = LEDS_0_BASE;uint16_t i, val;for(i = 0; i < 0xffff; ++i) {// IOWR_16DIRECT(leds, 0, i);
// val = IORD_16DIRECT(leds, 0);leds->led = i;val = leds->led;printf("zpwm: 0x%x\n", val);usleep(200000);}while(1);return 0;
}
没用?这就对了
如果把指针读写换成代码中注释掉的宏就可以了!
IOWR_16DIRECT(leds, 0, i);
val = IORD_16DIRECT(leds, 0);
之前说,Nios和STM32之类的单片差不多,为什么人家是一样的?难道是骗人的?有的同学就会说没有加volatile
。可是STM32的外设头文件也没加啊,而且加了也没用!难道Nios单独用了IO指令,和x86
一样也是IO
,Memory
分开的吗?外设里也没有涉及到IO/M#
信号呀?
这个问题就是经常提及的内存一致性问题,问题是为了提高数据访问速度的D-Cache
数据缓存造成的,循环中指针命中了缓存,D-Cache
完全由硬件电路负责,和编译器是没有关系的,编译器也很无奈。stm32没有D-Cache
,所以不存在这个问题,绕过D-Cache
,Nios有两种办法:
- 引入IO指令绕过
D-Cache
31bit
置1
绕过D-Cache
,会导致寻址范围降为2Gbit
内存一致性问题
D-Cache
是为了加速数据访问引入的,对程序是完全透明,而volatile
只能防止变量优化称寄存器,D-Cache
满天飞的时代这个关键字已经失去它原本的意义了,快要从标准中剔除了。Cortex-M3 M4都是没有D-Cache
只有I-Cache
,具体可以看stm32的内核和总线架构。Cortex-M7则出现了这个问题,stm32f7出现的问题,跨界内核有了AXI
总线和L1 Cache
这些高级玩意,自然不能幸免,和这个还不太一样,主要是两个问题,都是DMA一起用时出现的:
- RAM里的数据想DMA发送,可是
D-Cache
还没同步到RAM - DMA数据更新到了RAM,可是读取的还是
D-Cache
stm32f7里的的MPU设置了D-Cache
的地址范围,外设区间被禁用了,所以上面的问题也不会出现。
新姿势以后接着讲
Avalone细说就是一本几十页的手册,目前能用就好,以后慢慢来
参考文献
Making Qsys Components.pdf
Verilog自制NIOS2外设,Avalon总线上的HelloWorld相关推荐
- STM32外设有哪些?外设在总线上是怎么挂载的?
一:STM32外设有哪些? 外设在STM32库文件的下面路径下:(STM32库:stm32f10x_stdperiph_lib) stm32f10x_stdperiph_lib\STM32F10x_S ...
- python总线频率_跳上Avalon总线:一种简化的FPGA接口
引言本文引用地址:http://www.eepw.com.cn/article/201703/345268.htm 许多新式FPGA设计采用了一些用于控制的嵌入式处理器.一种典型解决方案需要使用诸如N ...
- 实现FPGA Verilog HDL与NIOS II的通信数据交换——利用AVALON总线
平时用FPGA基本都是全程用Verilog HDL编程,当遇到液晶的时候,发现Verilog的还不如C语言来的方便,但是用NIOS来编写的时候,实现NIOS与Verilog的通信又是一个问题,今天用了 ...
- Avalon总线概述
Nios系统的所有外设都是通过Avalon总线与Nios CPU相接的,Avalon总线是一种协议较为简单的片内总线,Nios通过Avalon总线与外界进行数据交换. Avalon总线接口分类 可分为 ...
- 关于AVALON总线动态地址对齐
在NIOS的使用中,我们往往要用到自定义外设,然后通过AVALON交换架构和NIOSII进行通信. AVALON总线,其实是一种交换架构的协议,在自定义外设挂在AVALON总线上时,一定要注意地址对齐 ...
- Qsys自定义组件的开始-Avalon总线规范(中文)
学习FPGA这么长时间了,一直没有整理自己的学习内容,这回要把每一段时间的学习内容总结一下,就从自定义组件开始吧.一定要坚持下来呀!! Avalon 总线规范 参考手册 (Avalon从端口传输与 ...
- 关于 avalon总线理解(整理)
1,一个基于Avalon接口的系统会包含很多功能模块,这些功能模块就是Avalon存储器映射外设,通常简称Avalon外设.所谓存储器映射外设是指外设和存储器使用相同的总线来寻址,并且CPU使用访问存 ...
- 将GPIO外设挂到Cortex_M3 AHB总线上详细流程扩展外设步骤总结
使用一个外设之前,你要弄明白这个外设是干什么的,它是怎样工作的,它的输入输出接口都是啥,你还要知道怎样给外设分配地址. GPIO的具体硬件结构在这里不多说了.(如果你要自己写代码,那硬件结构必须弄得明 ...
- Altera 的SOC器件之将自定义的IP挂在ARM硬核下(通过avalon总线),实现arm核与IP之间的通信
Altera 的SOC器件之将自定义的IP挂在ARM硬核下(通过avalon总线),实现arm核与IP之间的通信 软件: Quartus II 17.0 芯片: ALTERA Cyclone5 5CG ...
最新文章
- 站长如何短线操作实现盈利
- 温故一下Linux CentOS的VI/VIM命令
- Android中应用百度地图API开发地图APP实例-显示百度地图
- 对称加密算法之分组加密的六种工作模式(ECB、CBC、PCBC、CFB、OFB、CTR)
- matlab确定位置,Hurlin 的PSTR模型包,怎样确定位置参数个数
- [转]被当做狗和鸡来驱赶的百姓
- Method-Swizzling实战-实现iOS原生网络请求性能采集
- 高效数据序列化的工具 FlatBuffers 的初体验
- matplotlib制作多张图
- HDU-1045 Fire NetFire Net 最大团
- Struts2标签库(四)之非表单标签
- 深度卷积神经网络是什么,卷积神经网络结构设计
- 佛系宿华和他的“信任电商”伪命题
- #pragma once用法总结和链接错误
- Mysql分区表概述、分区类型、分区管理
- 网站被劫持到其它网站如何解决
- PhotoZoom Classic 7怎么样?对电脑和系统要求高不高?
- 图神经网络12-分子指纹GCN:Neural FPs
- Oracle数据库服务器IO高的分析方案和案例探讨
- python rest api 连接sdn控制器_基于REST-API的SDN控制器故障恢复机制
热门文章
- Java——【案例】Java坦克大战游戏[版本1]能控制移动的GUI界面坦克大战游戏
- 全国计算机等级考试三级网络技术考试经验分享(自学者使用)
- .netcore-线程池饿死问题分析(CPU空闲,并发量大时请求超时)
- 行业深度:区块链与金融、保险业那些不得不说的故事
- 忙碌的service(服务员)可能遇到要转发或者重定向的情况
- 第一节 使用ISM Web组态软件采集Modbus设备数据
- Union Find pros and cons
- mysql查找倒数_mysql倒数十条记录怎么查询
- 乐2Pro_乐视X625_官方线刷包_救砖包_解账户锁
- Pytorch教程入门系列3