使用不带Nios II处理器内核的Nios II处理器系统

在有关Redd的远程调试复合体的最后一篇文章中,我展示了使用该复合体不仅适用于FPGA。不仅如此,FPGA只是一个非常有趣的部分,但是仍然是该组合中非常具体的部分。它的主要部分是FTDI桥和其他USB设备。这个话题并没有引起太大的兴趣,但是,尽管如此,现在每个人都知道复杂系统中使用了哪种特定的硬件。再一次,我们可以回到一个有趣的话题——FPGA。

我们继承了上一个模块的传统,并继续寻找可选部件。今天,我们将学习如何在没有Nios II处理器内核的情况下进行操作。是的是的。在Nios II处理器系统中,处理器核心本身是重要的元素,但不是必需的元素。我们将练习在不使用该系统的情况下制作系统,将所有控制功能提高到Redd中心的中央处理器水平。




为什么需要处理器核心,为什么不需要


正如我在前一篇文章的理论部分已经提到的那样,当使用Redd复杂系统时,所有非标准设备都是辅助设备。它仅在项目阶段才短期使用,不会与客户疏远。因此,不太可能将各个开发人员分配给该人员。和他一起工作,学习太多其他东西是没有意义的。

这就是为什么我建议不要基于Verilog(或VHDL或其他某种特定语言)的开发方法,而只是基于现有设备创建Nios II系统,并将它们与总线连接。我选择了处理器核,而不是控制机,因为它的开发语言更接近于现代系统程序员。当然,如果没有足够的多维数据集创建系统,则必须添加缺少的多维数据集。但是随后它们可以在其他项目中重用,因此完成的库将很快被键入。

这种方法有很多优点。实际上,我们已经在实践中修复了此方法。但是,当我考虑要在讨论中提出的新示例时,FPGA存储器的匮乏便成为主流。我想为FIFO提供更多的内存,但是处理器的程序和数据也需要存储在某个地方。而且第四个旋风除尘器没有那么多的内存。每个人可能还不够。

第二个问题- 在上一篇文章中,我们已经制作了一个Nios II处理器和中央处理器之间的通信系统。它还占用了其FIFO的内存,此外-它的使用使图片混乱,隐藏了本文中描述的本质。如果您可以拒绝这种情况,则最好拒绝(尽管这种拒绝并非总是可能的)。

但是谁来管理系统?没有处理器内核又如何抛出数据?跟我碰面!组件Altera JTAG-to-Avalon-MM



一方面,它连接到标准JTAG总线(即标准总线,您不需要外部任何东西,只需通过标准USB-Blaster即可工作)。另一个连接到AVALON总线,可访问所有设备。处理器内核提供了完全相同的访问。最初,该单元是为了对其内核进行初始调试而设计的,以便从主机中唤醒。但是没有人禁止将其用于其他任务,因为Redd复合体中的JTAG适配器一直存在!

当然,基于此模块的系统无法提高交易效率。 JTAG通道本身并不快,但是基于Redd复合体中使用的微控制器的USB-Blaster适配器也使其完全放松。但是如何制作快速向导-我们已经知道了。没有人禁止每种情况选择对他来说更方便的方法。

在计划用于未来文章的项目中,管理速度并不关键。将会有一个分析器得到命令,将数据复制到SDRAM,之后它将进入自身,直到RAM已满或命令停止工作。这些命令将在几微秒或几十毫秒内执行-差别不大。

好吧,通过JTAG进行数据传输的速度将比通过FT245慢。但是话又说回来,我们已经知道如何通过FT245泵送所有东西。知道新的选择并不禁止我们选择旧的。但是,在熟悉了新选项之后,我们将有机会使系统变得更慢,但更易于开发,并且在资源方面更加经济。更多技术,不同而不同!因此,我们继续进行实验。

硬件


关于网络中硬件(相对于软件)的​​制造,有很多文章。通常,在所有示例中,内部FPGA存储器,LED和按钮都添加到了系统中。与整个国家一样,我们的组织现在已紧急地转移到一个偏僻的地方,所以我什至没有人要求将示波器连接到复杂的连接器,因此在此示例中,我将只限于记忆。谁将在普通面包板模型上重复实验,可以向输出添加GPIO以控制LED,并向输入添加GPIO以观察按钮的操作。我们创建了一个处理器系统(我在这里进行了描述),但是放置了Altera JTAG-to-Avalon-MM模块而不是处理器。他被带到这里:



好吧,我们增加了内存,以便至少可以检查今天的工作。接下来,我们将所有这些与总线连接,自动分配地址并获得如下信息:



请注意,复位信号的切换非常不标准。这是因为我不想花时间在它的实际生产上。

实际上,对于今天的设备-仅此而已。我们生成系统,分配clk支路(今天不使用其他支路)。我提醒您,我将复位支脚设为虚拟(虚拟引脚),本文介绍了过程(搜索短语“虚拟引脚”)。结果,结果应该是:



我们收集,填写FPGA ...我们继续进行实验。

通过TCL脚本编程


此外,所有讨论使用Altera JTAG-to-Avalon-MM块的教科书都说应该使用TCL脚本来完成这项工作。在冲入未知的深渊之前,最好先动手做一个有据可查的文件,这样我们就不会例外,我们也会着手进行实验。关于什么是TCL,有关哈布雷的文章很多。我将提供指向其中一个的链接,因为它与FPGA相关联:https : //habr.com/en/post/308962/。英特尔FPGA(以前的Altera网站)提供了使用该语言的完整在线课程。要了解如何在其上发出命令,您可以在开发环境中运行系统控制台:



结果,将打开一个华丽的环境。



直到GUI应用程序的开发,它都能发挥奇迹。但是,在本文的框架内,我们将仅从表面上讨论此问题(为什么-我稍后再解释)。我们只是尝试给几个团队。哪支球队?为此,您需要找到并下载文档“ 使用系统控制台分析和调试设计”(一如既往,我提供名称,但不提供链接,因为链接始终会更改)。

我们将尝试与该文档组的团队进行实验:



首先,请查看发送给我们的消息。由于我是从远程下载“固件”的,因此系统本身发现了一个远程JTAG服务器:



我们将在此窗口中发出命令:



首先,让我们尝试将一个常量写入内存。为此,您可以输入以下命令:

master_write_32

但是麻烦在于它的第一个参数是<service_path>。

因此,在提交有用的命令之前,您必须首先学习如何接收service_path我们正在文档中寻找合适的站点:



太好了!我们尝试使用文档中的示例来提交适当的命令。

% get_service_paths master
/devices/10CL006(Y|Z)|10CL010(Y|Z)|..@1#1-5.4.2.1#192.168.10.146/(link)/JTAG/alt_sld_fab_sldfabric.node_0/phy_0/master_0.master
%

不知何故很难手动输入。选项:
% lindex [get_service_paths master] 0
/devices/10CL006(Y|Z)|10CL010(Y|Z)| ..@1#1-5.4.2.1#192.168.10.146/(link)/JTAG/alt_sld_fab_sldfabric.node_0/phy_0/master_0.master
%

没有任何更好的。仅当有多个设备时,它才有用。

好。让我们尝试文档中示例的完整版本:

% set m_path [lindex [get_service_paths master] 0]
/devices/10CL006(Y|Z)|10CL010(Y|Z)|..@1#..@1#1-5.4.2.1#192.168.10.146/(link)/JTAG/alt_sld_fab_sldfabric.node_0/phy_0/master_0.master
%

现在-尝试记录:

% master_write_32 $m_path 0x0 0x01234567
error: master_write_32: /devices/10CL006(Y|Z)|10CL010(Y|Z)|..@1#..@1#1-5.4.2.1#192.168.10.146/(link)/JTAG/alt_sld_fab_sldfabric.node_0/phy_0/master_0.master is not an open master service
    while executing
"master_write_32 $m_path 0x0 0x01234567"
%

我们将继续研究说明...

% open_service master $m_path

%

现在可以工作吗?
% master_write_32 $m_path 0x0 0x01234567

% master_write_32 $m_path 0x4 0x89abcdef

%

没有错误讯息。我们尝试阅读:

% master_read_32 $m_path 0x0 0x2
0x01234567 0x89abcdef
%

作品!我们学会了写和读内存。设备寄存器也被投影到其上,因此将来我们将能够管理设备。
总体而言,正确的操作顺序如下所示:

set m_path [lindex [get_service_paths master] 0]
open_service master $ m_path
master_write_32 $ m_path 0x0 0x01234567
master_write_32 $ m_path 0x4 0x89abcdef
master_read_32 $ m_path 0x0 0x2

那些对系统控制台和TCL语言的功能感兴趣的人可以研究网络上数量众多的描述,示例和视频资料,在本文的框架内,我将继续介绍我个人在网络上找不到的内容...

从TCL移至C ++


TCL是一种相当强大的语言。进行研究总是很有用的,特别是如果您计划与FPGA紧密合作。通常,对于开发人员来说,流利使用另一种强大的编程语言是一大优势。但这就是全部。特别是,了解另一种语言的需求与本文中阐述的原则背道而驰。我们认为Redd复合体是辅助复合体,系统开发人员应该可以使用广泛的语言轻松地掌握它们。就是说,总是会说另一种语言,但这不是先决条件。

因此,我决定从旧的C / C ++中查找如何使用JTAG桥。但是,也许我是盲人,但是在花大量时间进行搜索查询汇编的练习时,我没有取得任何值得的成就。最有趣的是,许多请求给了我关于有趣的quartel的文章的链接,但它显示了如何从Java程序调用系统控制台,并且必须提前创建脚本文件,这显然会进一步破坏性能,而如果没有这样的话由于JTAG串行链接和缓慢的适配器,所以该比率不是很高。但是,使用Java的人员可以在内存中刷新该文章并采用方法。

一无所获,我决定使用PSoC系列文章之一中显示的原理。。该方法的本质很简单:如果没有文档,我们将研究交付内容。与Quartus一起完成的是许多TCL脚本。通过研究他们,我被语言的力量所深深吸引。但是,另一方面,我对如何花多少时间的想法深感困惑。是的,现在没有太多工作了,但是,首先,它仍然存在,其次,当您阅读这些内容时,我真的希望世界已经回到高速生活中。

最后,我找到了一个非常有趣的文件:C:\ intelFPGA_lite \ 17.1 \ quartus \ bin64 \ tcl_server.tcl

根据其内容判断,它会创建一个服务器,通过它您可以调用我们已经访问过的函数。也就是说,我们可以很好地编写我们的客户端,该客户端将通过网络连接并开始发出命令...该客户端可以用我最喜欢的C ++编写。也就是说,该问题将得到解决。因此,我们继续对该文件进行分析。

在本地计算机上试验tcl_server.tcl文件


我们继续在黑暗中从有据可查的目标过渡到隐藏的目标。我们正在尝试从Windows(在我的家用计算机上)学习所有内容,但是已经将其连接到远程JTAG服务器(在办公室的Redd综合大楼中)。

起初,调查走错了路。文件中有一个有趣的设计:

if { [info exists env(QUARTUS_ENABLE_TCL_SERVER)]  } {
	if { $env(QUARTUS_ENABLE_TCL_SERVER) == 1 } {
		_q_setup_server $_q_port
	}
}

当然,我将单词QUARTUS_ENABLE_TCL_SERVER放入搜索引擎。结果不多。只有两个。其中,只有一个值得:https : //www.intel.com/content/www/us/en/programmable/quartushelp/13.0/mergedProjects/eda/synthesis/synplicity/eda_pro_synplty_setup.htm

喜出望外,我创建了适当的环境变量,但是netstat –a命令显示端口2589上没有服务器。

好。然后,我尝试使用以下菜单项通过系统控制台运行整个脚本:



并且出现错误:



我是一个简单的人。在我的机器上没有找到关于此耻辱的描述(但在github上找到了它,并怀疑我们有简单的消息输出),我制作了一个脚本文件的副本并删除了相应的行:



在整个过程中,我删除了上述环境变量QUARTUS_ENABLE_TCL_SERVER的检查,因为无论如何我们必须手动运行脚本。

启动脚本后,侦听端口2589出现在系统中,您可以通过Telnet连接到它。我再次提醒您,目前我正在Windows家用计算机上进行实验。稍后我们将移至远程计算机。因此,我们已连接:



我们收到一个空的终端窗口。敲了几次键后,我们看到他们听到了我们的声音,但听不懂:



我们寻求帮助。

help
1 couldn't find help for command . Try help help.

已经更好了。澄清请求。

我只会显示答案的一部分:

help help 
<…>
get_service_paths
get_service_types
get_services_to_add
get_version
<…>
master_read_16
master_read_32
master_read_8
master_read_memory
master_read_to_file
master_write_16
master_write_32
master_write_8

熟悉的话!好吧,让我们尝试输入我们已经知道的行:

get_service_paths master
1 Error: Invalid command

抱歉! 但是我们只被允许发出get_service_paths命令

我们检查脚本中是否存在无效命令行她被发现在那里!
关于此设计的中间部分:

	set ecmd [lindex $line 0]
	if { $ecmd != "project" && $ecmd != "device" && 
	$ecmd != "cmp" && $ecmd != "sim" && $ecmd != "show_main_window"
	&& $ecmd != "hide_main_window" && $ecmd != "get_version" 
	&& $ecmd != "help" && $ecmd != "convert" 
	&& $ecmd != "import_assignments_from_maxplus2" } {
		set res "Error: Invalid command";
	} elseif [catch { set res [eval $line] } result] {
		set res "Error: $result";
	} 
	if { $res == "" } {
		set res " "
	}

事实证明,该脚本仅处理来自终端的少量命令。这实际上是一个非常有用的检查。将来,我们将能够在此位置处理脚本命令。当我们掌握TCL语言时,我们将能够将越来越多的代码带到脚本级别,并且仅从外部程序调用它(显然,这比通过网络驱动所有线路要快)。好吧,那些无法识别的命令仍然直接扔到解释器中。理想情况下,我们将慢慢研究TCL,然后逐步逐步进行。如果可以解决。

同时,停止执行脚本(关闭系统控制台),并用以下内容替换指定的部分:

	set ecmd [lindex $line 0]
	if [catch { set res [eval $line] } result] {
		set res "Error: $result";
	} 
	if { $res == "" } {
		set res " "
	}

我们运行脚本来执行,连接,尝试运行我们的参考命令序列:

set m_path [lindex [get_service_paths master] 0]
1 /devices/10CL006(Y|Z)|10CL010(Y|Z)|..@1#..@1#1-5.4.2.1#192.168.10.146/(link)/JTAG/alt_sld_fab_sldfabric.node_0/phy_0/master_0.master
open_service master $m_path
1 Error: can't read "m_path": no such variable

我们遗忘的变量。一方面,令人恶心。但是另一方面,我们将以编程方式填充行,因此将名称打包到参数中并不是那么麻烦。我们正在尝试提交详细的命令,在该命令中将不使用变量,而是使用变量的值。

open_service master /devices/10CL006(Y|Z)|10CL010(Y|Z)|..@1#..@1#1-5.4.2.1#192.168.10.146/(link)/JTAG/alt_sld_fab_sldfabric.node_0/phy_0/master_0.master 

我们得到了结果1.很棒!继续进行实验!

master_write_32 /devices/10CL006(Y|Z)|10CL010(Y|Z)|..@1#..@1#1-5.4.2.1#192.168.10.146/(link)/JTAG/alt_sld_fab_sldfabric.node_0/phy_0/master_0.master  0x0 0x01234567

master_write_32 /devices/10CL006(Y|Z)|10CL010(Y|Z)|..@1#..@1#1-5.4.2.1#192.168.10.146/(link)/JTAG/alt_sld_fab_sldfabric.node_0/phy_0/master_0.master 0x4 0x89abcdef

master_read_32 /devices/10CL006(Y|Z)|10CL010(Y|Z)|..@1#..@1#1-5.4.2.1#192.168.10.146/(link)/JTAG/alt_sld_fab_sldfabric.node_0/phy_0/master_0.master 0x0 0x2

我们得到答案:

1 0x01234567 0x89abcdef

1是执行功能的结果。接下来是读取的数据。也就是说,通过网络访问不是理想的,但是存在!

在远程计算机上使用tcl_server.tcl进行实验


通常,我们已经可以运行该程序并开始使用处理器系统,但是我们在JTAG设备的速度上增加了网络速度。当然,最好在远程计算机上运行工作程序,以使其在本地计算机上可以正常运行。因此,它将明显更快。就在那时,执行将在最初计划的Redd复合系统的中央处理器上进行。

要运行哪个文件?打破一些文档,找出quartus_sh是什么好。虽然我们不会喜欢脚本,但是,像在Windows中一样,我们将尝试以交互方式发出命令。展望未来,我会说这将很有趣。

因此,我们给出以下命令:

user@redd:~$ sudo /opt/intelFPGA/18.1/qprogrammer/bin/quartus_sh -s

我们提供提交tcl-lines的方法:



但是我们最喜欢的命令会导致错误:

tcl> get_service_paths master
invalid command name "get_service_paths"

事实证明,您需要通过提交两个命令来加载缺少的库:

load_package systemconsole 
initialize_systemconsole

没错,以下已经熟悉我们的团队甚至在使用库时也会出错:



哦,很长一段时间以来,我一直在寻找原因!我翻遍了所有图书馆,翻遍了搜索引擎上的大量文章,没有这样的团队。但是还有其他。但是它们不起作用。但是至少有。我不小心发现了一个不显眼的文档,并提供了解决方案。事实证明,我们需要Claim_path命令您好,一次又一次跨平台。

这个顺序将引导我们成功:
设置m_path [lindex [get_service_paths master] 0]
设置Claim_path [claim_service master $ m_path mylib]
master_write_32 $ Claim_path 0x0 0x01234567
master_write_32 $ Claim_path 0x4 0x89abcdef
master_read_32 $ Claim_path 0x0 0x2



通过Telnet检查


在交互模式下,一切正常,我们通过创建服务器的脚本检查工作。向其中添加缺少的行(加载库的两行)并运行:

user @ redd:〜$ sudo /opt/intelFPGA/18.1/qprogrammer/bin/quartus_sh -t tcl_server1.tcl

它崩溃。侦听套接字未出现。事实证明,我们需要添加不允许我们退出服务器打开功能的行:



相同的文字:
proc _q_setup_server {port} {
	global _q_lsock;
	if [catch { set _q_lsock [socket -server _q_accept $port] } emsg] {
	}
	vwait forever
	return;
}


我们运行正确的脚本,然后尝试通过Telnet连接到生成的服务器:



我们发出这样的命令(命令以粗体显示,答案以纯文本形式显示,例如在Windows中,我们用以前答案中的短语替换变量):

lindex [get_service_paths master]

1 {/ devices /10CL006(Y|Z)|10CL010(Y|Z)|..@1#1-5.4.2.1/(link)/JTAG/(110:132 v1#0)/ phy_0 / master}

Claim_service master {/ devices /10CL006(Y|Z)|10CL010(Y|Z)|..@1#1-5.4.2.1/(link)/JTAG/(110:132 v1#0)/ phy_0 / master} mylib

1 /通道/ remote1 / mylib / master_1

master_write_32 /通道/ remote1 / mylib / master_1 0x0 0x01234567

1

master_write_32 / channels / remote1 / mylib / master_1 0x4 0x89abcdef

1

master_read_32 / channel / remote1 / mylib / master_1 0x0 0x2

1 0x01234567 0x89abcdef

一切正常!

然后林务员来到了,分散了所有人……还是不是所有人?


在撰写本文时,我设法找到了一种有趣的技术,不需要编写可通过网络进行访问的脚本。 C具有popen函数(在Windows中为_popen)。它允许您通过捕获控制台程序的输入或输出流来打开其子进程。结果,在Windows上,您可以使用以下参数打开系统控制台:

C:\ intelFPGA_lite \ 17.1 \ quartus \ sopc_builder \ bin \ system-console.exe --disable_readline –cli

而且您可以在没有任何网络的情况下发出命令。但是麻烦在于我没有找到如何同时发送命令和接收答案的方法。_popen函数的参数只能是rw但不是两者都一次。有一种特定于Windows的技术,但它远非跨平台的。就像在Quartusel上的文章中一样,可以将脚本作为系统控制台程序的参数提交,并以流的形式获取答案,但每次启动都不会很快...

在Linux中,初始化系统控制台的功能也很慢,因此最好执行一次。 Google似乎说过,在Linux中popen函数具有参数“ r +”,它打开了双向通道。然后,我们可以打开quartus_sh并与之通信,但是我在Linux上不是很坚强,并且Google在没有解决方案的论坛上找到了链接,但对于是否在所有程序集中都存在争议,进行了激烈的辩论。

因此,我今天不会携带该程序。Telnet功能的实现可能是不必要的,但是我不知道如何制作一个理想的程序来拦截两个流。如果有人在评论中提供现成的解决方案,我将不胜感激。首先-在Debian下,以免通过网络驱动大量数据流。同时,我们将自己局限于一个可行的概念。

结论


我们熟悉基于Nios II开发的不直接包含处理器核心的处理器系统的方法。这样的系统不能被推荐为通用的,因为它们的速度还远远不够,但是在某些情况下,控制核心的速度并不是重要的因素。但是,在此类系统中实现内部RAM FPGA节省的成本就显得尤为重要。对于他们来说,推荐使用所描述的技术。

对此类系统进行编程的经典方法是TCL脚本,但是在Redd复杂概念的框架内,本文开发并描述了C ++编程方法。

可以从此处下载Quartus 17.1 Lite发行套件的源tcl_server.tcl脚本。编辑后获得的版本-在这里FPGA的示例项目可以在这里获得

All Articles