Nios II 嵌入式系统硬件设计(六)
最近一段时间一直在做SOPC用户自定义指令的设计,这里先写一篇自定义指令设计的硬件篇,后面还会陆续发布自定义指令设计的软件篇和实例篇,尽请期待啊。
在Nios II 系统设计中,遇到频繁使用的处理过程,而且该过程比较占用软件执行时间,设计人员可以考虑使用自定义元件或者自定义指令,用硬件来执行该处理过程,可以大大加快软件运行速度,自定义元件的设计请参考前面的文章:XXX,这本文中主要讲解如何在Nios II处理器中加入自定义指令,以提升执行速度。
在Nios II系统中总共支持256种自定义指令,用户添加的指令直接连接到Nios II处理器的算术逻辑单元,如下图所示:
为了适用各种应用情况,Nios II 支持以下四类自定义指令。
l 组合逻辑指令<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
组合逻辑指令接收两个变量输入(dataa,datab),经过组合逻辑运算后输出结果result。其中变量的输入个数可以是2个,1个或0个,但必须有结果输出。因为只涉及到组合逻辑运算,因此在一个系统周期便可以完成。需要注意的是在组合逻辑指令设计中避免使用外部接口,以免引起副作用。
指令的执行时序如下所示:
处理器在T1时刻提供输入变量的值dataa,datab,在下一个周期时刻T2,处理器采集result的值。
在Nios II安装软件目录的\example\verilog\custom_instruction_templates\Combinatorial中提供了组合逻辑指令的设计模板,设计人员可以在其基础上进行指令设计。
module custominstruction(
dataa, // Operand A (optional)
datab, // Operand B (optional)
result // result (always required)
);
//INPUTS
input [31:0] dataa;
input [31:0] datab;
//OUTPUTS
output [31:0] result;
// custom instruction logic (note: no external interfaces are allowed in combinatorial logic)
endmodule
l 多周期用户自定义指令
在组合逻辑指令中,设计人员只能进行组合逻辑运算,对于一些时序逻辑等功能更强大的运算则无能为力,这就需要设计多周期用户自定义指令。多周期指令有以下两种执行模式:
? 固定周期:及每次指令执行固定的周期后并返回结果。
? 可变周期:指令执行周期的数量不固定,需要用控制信号start,done来协调,start用来指明开始执行指令,done表示返回执行结果。
指令执行时序如下(可变周期):
在T1时刻start置高,表示开始执行指令,并提供输入变量dataa,datab,在T5时刻,指令执行完毕,将done置高,表示指令执行结束,同时返回执行结果result。
在Nios II安装软件目录的\examples\verilog\custom_instruction_templates\Multi_Cycle中提供了多周期用户指令的设计模板,设计人员可以在其基础上进行指令设计。
module custominstruction(
clk, // CPU system clock (always required)
reset, // CPU master asynchronous active high reset (always required)
clk_en, // Clock-qualifier (always required)
start, // Active high signal used to specify that inputs are valid (always required)
done, // Active high signal used to notify the CPU that result is valid (required for variable multi-cycle)
dataa, // Operand A (optional)
datab, // Operand B (optional)
result // result (always required)
);
//INPUTS
input clk;
input reset;
input clk_en;
input start;
input [31:0] dataa;
input [31:0] datab;
//OUTPUTS
output done;
output [31:0] result;
// custom instruction logic (note: external interfaces can be used as well)
endmodule
l 扩展用户自定义指令
在前面提到的自定义指令中,每条指令均只能执行一种功能,而扩展用户自定义指令在一条指令中可以执行多种功能,有序号N来决定每次调用指令时执行什么功能(比如N=0时执行为翻转功能,N=1时执行直接翻转功能,N=2时执行半字翻转功能等,如下图所示),N最大为8Bit宽,因此一条指令最多可以有256种功能。不过一条有3个功能的指令会占用4(因为用2bit表示N,2的2次方为4)个序号值,前面提到Nios II总共支持256种自定义指令,因此就只会余下256-4=252条指令空间。
扩展用户自定义指令的功能可以是组合逻辑指令实现或者是多周期用户自定义指令实现,只要在这两种指令的端口中添加N端口即可。
在Nios II安装软件目录的\examples\verilog\custom_instruction_templates\Extended中提供了扩展用户指令的设计模板,设计人员可以在其基础上进行指令设计。
module custominstruction
(
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)
start, // Active high signal used to specify that inputs are valid (required for extended multi-cycle)
done, // Active high signal used to notify the CPU that result is valid (required for extended variable multi-cycle)
n, // N-field selector (always required)
dataa, // Operand A (optional)
datab, // Operand B (optional)
result, // result (always required)
);
//INPUTS
input clk;
input reset;
input clk_en;
input start;
input [7:0] n; // modify width to match the number of unique operations within the custom instruction
input [31:0] dataa;
input [31:0] datab;
//OUTPUTS
output done;
output [31:0] result;
// custom instruction logic (note: external interfaces can be used as well)
// use the n[7..0] port as a select signal on a multiplexer to select the value to feed result[31..0]
endmodule
l 内部寄存器自定义指令
内部寄存器自定义指令可以读取指令的硬件描述文件中内部定义的寄存器的值作为指令的变量输入。指令通过输入控制端口readra,readrb来控制读取的变量是dataa,datab还是内部寄存器的值以及使用writerc来控制输出到result还是到内部寄存器,如果readra,readrb和writerc输入高电平,指令读取dataa和datab作为比变量输入,并把结果输出到result中,如果readra和readrb输入低电平,则指令读取内部寄存器的值,并把结果输出到内部寄存器中,具体读取和输入到哪一个寄存器有a,b,c决定,内部寄存器的读写数量可以达到32个,,所以a,b,c均为5bit宽度。
上图即为用内部寄存器自定义指令实现的一个乘加操作,首先writerc为低电平,将dataa和datab的乘积输入到内部寄存器Adder中,然后writerc变为高电平,Adder结果与dataa相加并输出到result中,同时轻清零D触发器的值。
在Nios II安装软件目录的\examples\verilog\custom_instruction_templates\ Internal_Register_File中提供了内部寄存器自定义指令的设计模板,设计人员可以在其基础上进行指令设计。
module custominstruction(
clk, // CPU system clock (required for multi-cycle or extended multi-cycle)
reset, // CPU master asynchronous active high reset (required for multi-cycle or extended multi-cycle)
clk_en, // Clock-qualifier (required for multi-cycle or extended multi-cycle)
start, // Active high signal used to specify that inputs are valid (required for multi-cycle or extended multi-cycle)
done, // Active high signal used to notify the CPU that result is valid (required for variable multi-cycle or extended variable multi-cycle)
n, // N-field selector (required for extended)
dataa, // Operand A (optional)
datab, // Operand B (optional)
a, // Internal operand A index register
b, // Internal operand B index register
c, // Internal result index register
readra, // Read operand A from CPU (otherwise use internal operand A)
readrb, // Read operand B from CPU (otherwise use internal operand B)
writerc, // Write result to CPU (otherwise write to internal result)
result // Result (always required)
);
//INPUTS
input clk;
input reset;
input clk_en;
input start;
input [7:0] n; // modify width to match the number of unique operations within the custom instruction
input [4:0] a;
input [4:0] b;
input [4:0] c;
input readra;
input readrb;
input writerc;
input [31:0] dataa;
input [31:0] datab;
//OUTPUTS
output done;
output [31:0] result;
// custom instruction logic (note: external interfaces can be used as well)
// use the n[7..0] port as a select signal on a multiplexer to select the value to feed result[31..0]
endmodule
不过内部寄存器自定义指令只能通过汇编语言实现,比如:
Custom 0, r6, r7, r8
Custom 0, c1, r2, c4
他们使用的是同一种命令,但是结果却是完全不一样的。R 代表的是Nios II的内部寄存器,r6, 代表的就是6号寄存器。C 代表的是自定义指令的内部寄存器,c4就是4号寄存器。所以第一个指令是说,我们来使用0号自定义指令来操作,操作的输入为 R7和R8, 而输出存放在R6里面。而第二个指令是说,我们来使用0号自定义指令,而操作的输入为r2和c4,就是Nios II的2号寄存器和自定义指令里面的4号寄存器,结果放回到C1就是自定义指令的1号寄存器。通过这种方法我们来完成internal register file这种模式的自定义指令。
l 带外部接口的自定义指令
该指令允许在执行时与外界(SOPC系统外部环境)进行通信,将需要与外界通信的端口定义成conduit端口即可以建立起和外界通信。允许与外界通信大大的增加了自定义指令的功能,指令可以读取外界数据进行计算,也可以将计算结果输出到外界,或者将寄存器的值输出到外界FIFO进行存储等。
带外部接口的自定义指令并不是单独的一条指令,将前面提到的指令只要能加上conduit端口与外界进行通信均可以设计成带外部接口的自定义指令。
gxj-123_620130386 2008-12-22 22:39