nios自定义外设教程
- 格式:pdf
- 大小:163.72 KB
- 文档页数:10
NIOS教程(1) --------建立一个最小系统简介NIOS是一个用户可配置的通用32位RISC嵌入式处理器,它是SOPC(System On a Programmable Chip,片上可编程系统)的核心。
处理器以软核形式实现,具有高度的灵活性和可配置性。
NIOS的开发包括硬件开发和软件开发两部分。
硬件开发是在Quartus II中实现的,而软件开发部分是在NIOS IDE软件中实现的。
我们首先来介绍NIOS的硬件逻辑开发。
所谓硬件逻辑开发就是用Quartus II 和 SOPC Builder来建立自己需要的软核。
1.先打开QuartusII 9.0SP2软件点击菜单栏FileÆ New Project Wizard,弹出如下对话框点击Next>按钮继续,在此步中,What is the working directory for this project? 是询问你的这个项目工程打算放在哪里?我们改为d:\ask2cb_nios\nios1 (表示整个工程建立在D盘的ask2cb_nios\nios1目录下面) What is the name of this project? 是询问你这个工程项目名是什么?我们改为nios1(表示这是第一个nios示例工程)What is the name of the top-level design entity for this project? 是询问这个工程项目的顶层设计入门名我们改为nios1,表示顶层模块名为nios1改成如下图所示:点击Next>继续提示D盘下面没有ask2cb_nios目录下的nios1这个目录,询问是否要创建它,选择是(y),让QuartusII创建这个目录。
向导开始询问是否有现成的文件需要加到当前新建的工程中?这步不用管它,点击Next>继续,在此步中,向导询问你使用的是何种器件,我们在Device family组合框中,Family下拉列表中选择CycloneII,在Available devices:下面的列表框中选择EP2C5Q208C8,这是我们ASK2CB-5开发板所使用的FPGA主芯片(EP2C5Q208C8),如果您购买的是ASK2CB-8开发板,请选择EP2C8Q208C8。
S O P C中自定义外设和自定义指令性能分析■东北电力大学 王玉峰■聊城工业学校 郭春凤 摘 要NiosII是一个建立在FP GA上的嵌入式软核处理器,灵活性很强。
作为体现NiosII灵活性精髓的两个最主要方面,自定义外设和自定义指令的性能开始受到越来越多开发者的关注。
本文在对NiosII自定义外设和自定义指令进行深入研究后,采用实验的方法,通过实例CRC232对比了在实现相同功能的情况下,自定义外设和自定义指令的性能差异,并从自定义外设和自定义指令的实现机理上给予说明。
分析结果表明:在SOPC系统中,如果系统的实时性要求非常高,那么采取自定义外设来实现系统中关键处理模块无疑是最佳选择。
关键词自定义外设 自定义指令CRC校验性能分析 SOPC引 言NiosII是一个嵌入式软核处理器,除了可以根据需要任意添加已经提供的各种外设以外,用户还可以通过定制自定义外设和自定义指令的方式来满足各种应用需求。
定制用户外设和用户指令是使用NiosII嵌入式软核处理器的重要特征。
定制的用户外设能够以“硬件加速器”的形式实现各种各样用户要求的功能;同时定制的用户指令,可以把一个复杂的标准指令序列简化为一条用硬件实现的单个指令,以增强对实时软件算法的处理能力。
近来,随着国内SOPC开发的逐步深入,这两者的性能开始成为一个关注的焦点。
本文通过CRC232对SOPC系统中的自定义外设和自定义指令的实现以及对性能差异所作的详细分析,给广大SOPC开发人员提供参考。
1 CRC自定义外设的实现1.1 SOPC系统中自定义外设的组成和结构自定义外设作为NiosII软核处理器超强灵活性的体现,其开发遵循一定的规律。
一个用户自定义外设必须进行硬件设计,也就是说,必须用硬件描述语言来描述出硬件的逻辑组成。
一般来说,一个自定义外设主要由下列部分组成:①描述自定义外设逻辑的硬件描述文件部分(主要是HDL程序)。
②软件文件,一个用来定义外设寄存器的C语言头文件,以及让程序员控制这个元件的软件驱动程序。
NIOS软件设计流程和方法1软件开发包NIOS嵌入式处理器是经过专门优化过的软核CPU,以便于在可编程逻辑器件上实现SOPC设计。
Altera。
公司提供SOPC Buildei。
系统开发工具,来帮助用户创建采用NIOS处理器的软硬件系统:硬件设计师利用SOPC Builder构建软硬件开发的基础,SOPC Builder的生成结果将作为特定用户设计的开发软件的起点。
当SOPC Builder生成一个NIOS处理器设计时,会完成以下工作:1.系统存储器映像的一致性检查。
对外设地址和中断优先级进行惟一性验证,检查其是否在CPU的有效访问范围之内。
如果不是,报告相应的错误,并在继续下一步以前修正。
2.为NIOS系统生成一个定制的软件开发包(Soflw~e Development Kit,SDK)。
3.生成NIOS处理器系统的硬件设计文件。
硬件设计师可以用这些文件来创建NIOS系统硬件。
1.1软件开发流程在进行NIOS软件开发时,通常按照下面的过程进行。
步骤1:获得目标N10S系统的SDK从SOPC Builder创建的工程目录中(或从负责NIOS处理器硬件系统的设计师那里)得到目标NIOS处理器系统的SD K。
软件开发环境的基础是由SOPC Builder生成的SDK目录。
SDK中包含的头文件和库文件,提供了硬件映像地址和一些基本的硬件访问子程序,有效地减少了原有分工模式下的软硬件衔接工作。
步骤2:建立和编译应用软件首先使用文本编辑器,用C/C++或汇编语言编写应用程序的源代码(.c或.s);然后使用nios-build命令或Makef ile将源代码编译成可执行代码。
编译产生的二进制码以S-record的格式(.sere)存储。
对于一个小型或中型的软件项目,使用nios-build就可以编译生成可执行代码:对于一个大型项目,则必须参照由SOPC Builder生成的示例Makefi le编写自己的Makefile,来编译生成可执行代码。
NIOSii配置及例程使用教程NIOS ii 配置及例程使用教程本教程为nios ii在FPGA板上的配置入门教程,仅使用在xsyan 设计制作EP2C5/EP2C8开发板上。
下面将会详细的说明如何使用nios ii在FPGA上配置一个altera公司提供的CPU,并利用这个CPU 来调试和执行相应C程序。
并且,最后会有两个例程。
一,硬件要求:1,EP2C5/EP2C8开发板一块。
2,USB电源线一条。
3,并口线一条。
4,串口线一条。
二,软件要求:1,quartus II 7.0.2,MegaCore IP 7.0.3,Nios II EDS 7.0.三,主要步骤:1,在quartus上创建一个工程。
2,在此工程里面调用SOPC,并配置CPU。
3,创建cpu.4,定义FPGA引脚并综合。
5,调用NIOS,配置相应设置。
6,再次编译综合工程。
7,下载FPGA。
四,详细步骤:1,在quartus上创建一个工程。
a)打开quartus,选择File->New project wizard.b)在打开的窗口上选择Nextc)选择工程路径,并且指定工程名字。
d)添加文件,因为没有设计文档,所以跳过,直接Next。
e)选择器件,请根据自己的开发板选择EP2C5T144C8/ EP2C8T144C8f)然后直接点Finish,创建工程完毕。
2,用SOPC配置一个CPU。
a)在quartus里面调用SOPC。
b)在打开的SOPC里面,输入系统名字,选择HDL语言种类c)点确定后开始配置CPU,双击左边栏的Nios ii Processor.d)这里选择经济型,然后点Next,直到下个页面。
e)然后点finish,Process配置结束,双击UART,配置串口f)直接用默认配置,点Finish即可,然后双击on-chip-memory 配置memory。
g)配置如上图配一个8K内部ram后点Finish,用来存放程序代码和初始化代码,然后继续创建memory用来存放变量,再创建两个4K内部ram,步骤同上。
NIOS II Step by Step一、 创建Quartus II工程1、打开Quartus II环境。
开始Æ程序ÆAlteraÆQuartus II 5.1。
2、点主菜单FileÆNew Project Wizard…,创建新工程。
3、弹出如下窗口,点Next,进行下一步操作。
4、输入新建工程路径,工程名及工程顶层实体,点Next,下一步。
如所输入工程路径文件夹不存在,则会弹如下窗口,点“是”,创建工程文件夹。
5、弹出如下窗口,按默认,点Next,下一步操作。
6、选择目标板上对应的正确芯片型号,点Next,下一步操作。
7、设置适当工具选项,可按默认不设置,点Next,下一步。
8、点Finish,完成工程结构创建。
9、鼠标指向Project Navigator窗口中工程器件项,右击鼠标选择器件属性设置“Device…”10、选择Device & Pin Option,进行器件及管脚选项设置。
11、选择配置项Configuration,选择配置芯片与目标板上配置器件一致。
12、选择Unused Pins选项,把没用到管脚设为三态输入“As input tri-stated”,其它选项按默认,点确定,完成设置。
二、SOPC Builder创建系统模块1、在Quartus II环境中选择菜单ToolsÆSOPC Builder…,打开SOPC Builder向导。
2、创建新系统,输入系统模块名称,如“Techshine_EP1C12”,选择适当的目标描述语言。
3、在左端元件池窗口列表中选处理器项,点Add…或双击鼠标左键,添加CPU。
4、选择适当的NIOS II Core,推荐用“Nios II/s”模式,点Next,进一步设置5、对Cashes & Tightly Coupled Memories设置,可选择默认,点Next,下一步设置。
NIOS ii系统添加外部接口读写总线实例软件环境:quartus ii 11.0本实例使用quartus ii 的Qsys工具建立NIOS ii系统。
Qsys工具只提供部分标准外部存储器件的读写控制模块,如下图示:对于一般外部地址空间的访问,需要用户自定义接口控制模块,然后挂接在NIOS ii Avalon总线上,实现外部空间的读写功能。
下面通过实例演示总线的添加及使用过程。
首先建立所需的外部接口总线控制模块(verilog module),本例建立ADV212_interface模块,对应的文件名称为ADV212_interface.v,端口描述如下:定义avalon 总线和外设的互联关系,需要关注外设的总线宽度和地址空间大小,如下图:下面生成外设控制模块,首先打开component Editor窗口,如下图:弹出对话框如下,点击Add添加ADV212_interface.v,点击NextSignals选项卡定义信号接口关系。
首次定义avalon总线Interface 选择new Avalon Memory Mapped Slave…,生成avalon-slave接口,此处为s0,如下图:首次定义外部接口信号Interface选择new Conduit将产生conduit_end,然后依次选择,Signal Type选择export依次选择其他选项,最终结果如下,点击Next进入Interface选项。
如果Remove Interfaces With No Signals有效(见下图红色方框内),点击一下。
设置其他选项,关注红色区域,如下图:下拉右侧滚动条,设置总线Timing 参数:下拉右侧滚动条,设置clock,reset:下拉右侧滚动条,设置conduit_end,点击Next进入HDL Parameters选项卡,点击Next进入Library Info选项卡,设置模块名称,点击Finish此时,在左侧component library窗口将出现刚生成的user_bus1模块,将其添加进右侧System contents窗口,然后重新分配地址和中断向量,最后在点击generation,生成NIOS ii。
自定义指令设计定义指令是基于NIOSII处理器SOPC系统的一个重要特征。
NIOSII处理器定制指令不仅扩展了CPU的指令集,还能提高对时间要求严格的软件运行速度,因此提高了系统的整体性能。
采用定制指令,用户可以实现传统处理器无法达到的最佳性能。
在对数据处理速度要求比较高的场合,把由标准指令序列实现的核心功能变成由一个用于定制的指令来实现,可以明显提高软件的执行效率。
给予硬件处理模块的定制指令可通过单个时钟周期或者多个时钟周期的硬件算法操作完成原本十分复杂的处理任务。
NIOSII处理器最多支持256条的定制指令,加速通常由软件实现的逻辑和复杂的数学运算。
具有定制指令的NiosII硬件结构如图1所示。
图1具有定制指令的NiosII硬件结构用户指令实质上就是让软核处理器完成由硬件逻辑实现的某种功能,这个硬件逻辑连接到NIOSII处理器的算术逻辑单元上。
对于NIOSII的标准指令,NIOSII使用ALU来完成相应的算术逻辑操作;对于自定义指令,则采用用户自己建立的硬件逻辑来完成运算。
用户指令分多种,有组合逻辑指令、多周期指令、扩展指令等等,学明白一个,也就举一反三了, Altera提供了用户模块HDL的模板,通过裁减就可以适应多种指令类型了。
模板存放的路径为:\altera\kits\nios2\examples\verilog\custom_instruction_templates用户指令逻辑模块结构如图2所示。
z图2 用户指令逻辑结构例子:// Verilog Custom Instruction Template File for Combinatorial Logicmodule ci_nand(dataa, // Operand A (always required)datab, // Operand B (optional)result // result (always required));//INPUTSinput [31:0] dataa;input [31:0] datab;//OUTPUTSoutput [31:0] result;// custom instruction logic (note: no external interfaces are allowed in combinatorial logic)assign result = ~(dataa&datab);endmodule#include "stdio.h"#include "system.h"#include "sys/alt_timestamp.h"#include "alt_types.h"int main(void){alt_u32 time1,time2;alt_u32 a,b,c;a = 0xff00ff00;b = 0xf0f0f0f0;if (alt_timestamp_start() < 0){ //开启时间标记服务printf("Can't Start Timestamp...\n");}time1 = alt_timestamp(); //测试时间点1c = ALT_CI_CI_NAND(a,b); //通过宏使用定制指令time2 = alt_timestamp(); //测试时间点2printf("The Instruction ci_nand runs %ld\n",time2-time1);printf("c = %x\n",c);time1 = alt_timestamp(); //测试时间点1c = ~(a&b); //通过NiosII指令实现与非功能time2 = alt_timestamp(); //测试时间点2printf("The ~(a&b) runs %ld\n",time2-time1);printf("c = %x\n",c);return 0;}在生成的system.h文件中,关于CRC自定义指令的宏如下:#define ALT_CI_CI_NAND_N 0x00000000#define ALT_CI_CI_NAND(A,B) __builtin_custom_inii(ALT_CI_CI_NAND_N,(A),(B))。
“ALT_“是宏定义的前缀,表示为Altera公司,CI是用户定制指令的意思。
CI_NAND是用户指令的逻辑模块名称,N表示指令操作码。
module mul16(clk, // CPU system clock (required for extended multi-cycle)reset, // CPU master asynchronous active high reset (required for extended multi-cycle)clk_en, // Clock-qualifier (required for extended multi-cycle)dataa, // Operand A (always required)datab, // Operand B (optional)result, // result (always required) );//INPUTSinput clk;input reset;input clk_en;input [31:0] dataa;input [31:0] datab;//OUTPUTSoutput [31:0] result;reg [31:0] result;always @(posedge clk or negedge reset)beginif (!reset)result <=0;elseresult<=dataa[15:0]*datab[15:0] ;endendmodule#include<stdio.h>#include<math.h>#include "system.h"int alt_main(){int a,b;int c;a=7;b=8;c=ALT_CI_MUL16(a,b);printf("result is %d\n",c);return (0);}自定义外设作为NIOSII软核处理器超强灵活性的体现,其开发遵循一定的步骤。
一般来说,一个定制元件主要由下列部分组成。
1、描述元件逻辑的硬件描述文件部分(主要是HDL程序)2、软件文件,一个用来定义元件寄存器的C语言头文件以及让程序员控制这个元件的软件驱动程序。
3、元件的描述文件(class.ptf),该文件定义了元件的架构,提供了SOPC Builder将该元件集成到一个系统的各种信息。
在文件由元件编辑器根据用户提供的硬件和软件文件以及在图形用户界面中设置的各个选项和参数自动生成。
图1给出了带Avalon从端口的元件组成框图图1带Avalon从端口的用户外设组成框图从图中可以看出,一个自定义外设必须进行硬件设计。
一个典型的用户外设主要由下列功能模块组成:(1)任务逻辑。
任务逻辑完成元件的基本功能,是必不可少的组成部分。
(2)寄存器文件。
寄存器文件部分提供了任务逻辑和外界交换信息的桥梁。
有了寄存器文件,用户就可以通过Avalon接口采用基地址+地址偏移量的方法来访问元件内部的各个寄存器。
(3)Avalon接口。
Avalon接口为寄存器文件提供了一个标准的Avalon前端。
该模块使用Avalon规定的信号来访问寄存器文件,并且支持任务逻辑的传输类型。
module avalon_pwm(clk, wr_data, byte_n, cs, wr_n, addr, clr_n, rd_data, pwm_out);input clk;input [31:0] wr_data;input [3:0] byte_n;input cs;input wr_n;input addr;input clr_n;output [31:0] rd_data;output [7:0] pwm_out;reg [7:0] div3, div2, div1, div0;reg [7:0] duty3, duty2, duty1, duty0;reg [31:0] counter;reg off;reg [31:0] rd_data;wire div_en3, div_en2, div_en1, div_en0, duty_en3, duty_en2, duty_en1, duty_en0;always @(posedge clk or negedge clr_n)beginif (clr_n == 0)begindiv3 <= 8'h 00;div2 <= 8'h 00;div1 <= 8'h 00;div0 <= 8'h 00;duty3 <= 8'h 00;duty2 <= 8'h 00;duty1 <= 8'h 00;duty0 <= 8'h 00;endelsebeginif (div_en3)div3 <= wr_data[31:24];elsediv3 <= div3;if (div_en2)div2 <= wr_data[23:16];elsediv2 <= div2;if (div_en1)div1 <= wr_data[15:8];elsediv1 <= div1;if (div_en0)div0 <= wr_data[7:0];elsediv0 <= div0;if (duty_en3)duty3 <= wr_data[31:24];elseduty3 <= duty3;if (duty_en2)duty2 <= wr_data[23:16];elseduty2 <= duty2;if (duty_en1)duty1 <= wr_data[15:8];elseduty1 <= duty1;if (duty_en0)duty0 <= wr_data[7:0];elseduty0 <= duty0;endendalways @(posedge clk or negedge clr_n)beginif (clr_n == 0)counter <= 0;elseif (counter >= {div3, div2, div1, div0})counter <= 0;elsecounter <= counter + 1;endalways @(posedge clk or negedge clr_n)beginif (clr_n == 0)off <= 0;elseif (counter >= {duty3, duty2, duty1, duty0}) off <= 1;elseif (counter == 0)off <= 0;elseoff <= off;endalways @(addr or div3 or div2 or div1 or div0 or duty3 or duty2 or duty1 or duty0) if (addr == 0)rd_data = {div3, div2, div1, div0};elserd_data = {duty3, duty2, duty1, duty0};assign div_en3 = cs & !wr_n & !addr & !byte_n[3];assign div_en2 = cs & !wr_n & !addr & !byte_n[2];assign div_en1 = cs & !wr_n & !addr & !byte_n[1];assign div_en0 = cs & !wr_n & !addr & !byte_n[0];assign duty_en3 = cs & !wr_n & addr & !byte_n[3];assign duty_en2 = cs & !wr_n & addr & !byte_n[2];assign duty_en1 = cs & !wr_n & addr & !byte_n[1];assign duty_en0 = cs & !wr_n & addr & !byte_n[0];assign pwm_out[0] = ! off;assign pwm_out[1] = ! off;assign pwm_out[2] = ! off;assign pwm_out[3] = ! off;assign pwm_out[4] = ! off;assign pwm_out[5] = ! off;assign pwm_out[6] = ! off;assign pwm_out[7] = ! off;endmodule#ifndef __ALTERA_AVALON_PWM_REGS_H__#define __ALTERA_AVALON_PWM_REGS_H__#include <io.h>#define IORD_ALTERA_AVALON_PWM_DIVIDER(base) IORD(base, 0)#define IOWR_ALTERA_AVALON_PWM_DIVIDER(base, data) IOWR(base, 0, data)#define IORD_ALTERA_AVALON_PWM_DUTY(base) IORD(base, 1)#define IOWR_ALTERA_AVALON_PWM_DUTY(base, data) IOWR(base, 1, data)#endif /* __ALTERA_AVALON_PWM_REGS_H__ */#include <stdio.h>#include "altera_avalon_pwm.h"#include "system.h"int main(){int rx_char;char line[100];printf("Hello from Nios II!\n");printf("Nios II Training Lab\n");printf("March 18, 2003\n");printf("\nPlease enter an LED intensity between 1 to 4 (0 to exit)\n");IOWR_ALTERA_AVALON_PWM_DIVIDER(MY_PWM_BASE,0xFF);IOWR_ALTERA_AVALON_PWM_DUTY(MY_PWM_BASE,0xFF);while (1){fgets(line, sizeof(line),stdin);sscanf(line,"%d",&rx_char);switch (rx_char){case 4:IOWR_ALTERA_AVALON_PWM_DUTY(MY_PWM_BASE,0xFF);printf("Level 4 intensity\n");break;case 3:IOWR_ALTERA_AVALON_PWM_DUTY(MY_PWM_BASE,0x80);printf("Level 3 intensity\n");break;case 2:IOWR_ALTERA_AVALON_PWM_DUTY(MY_PWM_BASE,0x30);printf("Level 2 intensity\n");break;case 1:IOWR_ALTERA_AVALON_PWM_DUTY(MY_PWM_BASE,0x10);printf("Level 1 intensity\n");break;case 0:return 0;break;default:printf("Please enter an integer value from 0 to 4\n");break;}}return 0;}。