虚无的目录

  • 嘿嘿嘿,开新坑
  • 这个时候有个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总线,用inout指令访问,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有很多,就不在此举出了。

  1. Qsys配置新组件,随便起个名字
  2. 选择文件,和顶层入口
  3. 信号设置
    设置后的信号如上图,需要设计的也就Q_export,设置为conduit_end导出IO。
  4. 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一样也是IOMemory分开的吗?外设里也没有涉及到IO/M#信号呀?

这个问题就是经常提及的内存一致性问题,问题是为了提高数据访问速度的D-Cache数据缓存造成的,循环中指针命中了缓存,D-Cache完全由硬件电路负责,和编译器是没有关系的,编译器也很无奈。stm32没有D-Cache,所以不存在这个问题,绕过D-Cache,Nios有两种办法:

  • 引入IO指令绕过D-Cache
  • 31bit1绕过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相关推荐

  1. STM32外设有哪些?外设在总线上是怎么挂载的?

    一:STM32外设有哪些? 外设在STM32库文件的下面路径下:(STM32库:stm32f10x_stdperiph_lib) stm32f10x_stdperiph_lib\STM32F10x_S ...

  2. python总线频率_跳上Avalon总线:一种简化的FPGA接口

    引言本文引用地址:http://www.eepw.com.cn/article/201703/345268.htm 许多新式FPGA设计采用了一些用于控制的嵌入式处理器.一种典型解决方案需要使用诸如N ...

  3. 实现FPGA Verilog HDL与NIOS II的通信数据交换——利用AVALON总线

    平时用FPGA基本都是全程用Verilog HDL编程,当遇到液晶的时候,发现Verilog的还不如C语言来的方便,但是用NIOS来编写的时候,实现NIOS与Verilog的通信又是一个问题,今天用了 ...

  4. Avalon总线概述

    Nios系统的所有外设都是通过Avalon总线与Nios CPU相接的,Avalon总线是一种协议较为简单的片内总线,Nios通过Avalon总线与外界进行数据交换. Avalon总线接口分类 可分为 ...

  5. 关于AVALON总线动态地址对齐

    在NIOS的使用中,我们往往要用到自定义外设,然后通过AVALON交换架构和NIOSII进行通信. AVALON总线,其实是一种交换架构的协议,在自定义外设挂在AVALON总线上时,一定要注意地址对齐 ...

  6. Qsys自定义组件的开始-Avalon总线规范(中文)

    学习FPGA这么长时间了,一直没有整理自己的学习内容,这回要把每一段时间的学习内容总结一下,就从自定义组件开始吧.一定要坚持下来呀!! Avalon 总线规范 参考手册   (Avalon从端口传输与 ...

  7. 关于 avalon总线理解(整理)

    1,一个基于Avalon接口的系统会包含很多功能模块,这些功能模块就是Avalon存储器映射外设,通常简称Avalon外设.所谓存储器映射外设是指外设和存储器使用相同的总线来寻址,并且CPU使用访问存 ...

  8. 将GPIO外设挂到Cortex_M3 AHB总线上详细流程扩展外设步骤总结

    使用一个外设之前,你要弄明白这个外设是干什么的,它是怎样工作的,它的输入输出接口都是啥,你还要知道怎样给外设分配地址. GPIO的具体硬件结构在这里不多说了.(如果你要自己写代码,那硬件结构必须弄得明 ...

  9. Altera 的SOC器件之将自定义的IP挂在ARM硬核下(通过avalon总线),实现arm核与IP之间的通信

    Altera 的SOC器件之将自定义的IP挂在ARM硬核下(通过avalon总线),实现arm核与IP之间的通信 软件: Quartus II 17.0 芯片: ALTERA Cyclone5 5CG ...

最新文章

  1. 站长如何短线操作实现盈利
  2. 温故一下Linux CentOS的VI/VIM命令
  3. Android中应用百度地图API开发地图APP实例-显示百度地图
  4. 对称加密算法之分组加密的六种工作模式(ECB、CBC、PCBC、CFB、OFB、CTR)
  5. matlab确定位置,Hurlin 的PSTR模型包,怎样确定位置参数个数
  6. [转]被当做狗和鸡来驱赶的百姓
  7. Method-Swizzling实战-实现iOS原生网络请求性能采集
  8. 高效数据序列化的工具 FlatBuffers 的初体验
  9. matplotlib制作多张图
  10. HDU-1045 Fire NetFire Net 最大团
  11. Struts2标签库(四)之非表单标签
  12. 深度卷积神经网络是什么,卷积神经网络结构设计
  13. 佛系宿华和他的“信任电商”伪命题
  14. #pragma once用法总结和链接错误
  15. Mysql分区表概述、分区类型、分区管理
  16. 网站被劫持到其它网站如何解决
  17. PhotoZoom Classic 7怎么样?对电脑和系统要求高不高?
  18. 图神经网络12-分子指纹GCN:Neural FPs
  19. Oracle数据库服务器IO高的分析方案和案例探讨
  20. python rest api 连接sdn控制器_基于REST-API的SDN控制器故障恢复机制

热门文章

  1. Java——【案例】Java坦克大战游戏[版本1]能控制移动的GUI界面坦克大战游戏
  2. 全国计算机等级考试三级网络技术考试经验分享(自学者使用)
  3. .netcore-线程池饿死问题分析(CPU空闲,并发量大时请求超时)
  4. 行业深度:区块链与金融、保险业那些不得不说的故事
  5. 忙碌的service(服务员)可能遇到要转发或者重定向的情况
  6. 第一节 使用ISM Web组态软件采集Modbus设备数据
  7. Union Find pros and cons
  8. mysql查找倒数_mysql倒数十条记录怎么查询
  9. 乐2Pro_乐视X625_官方线刷包_救砖包_解账户锁
  10. Pytorch教程入门系列3