带有高级语言编译器或鼠标之歌的本地FPGA软处理器

具有高级语言编译器或鼠标之歌的自己的FPGA软处理器-具有使高级语言编译器适应堆栈处理器内核的经验。

软件处理器的一个普遍问题是缺乏针对它们的开发工具,尤其是在其指令系统不是其流行的处理器内核之一的指令的子集的情况下。在这种情况下,开发人员必须解决此问题。它的直接解决方案是创建汇编语言编译器。但是,在现代现实中,在Assembler中工作并不总是很方便,因为在项目开发过程中,命令系统可能会由于例如变化的需求而发生变化。因此,与为软件处理器轻松实现高级语言编译器(JAV)的任务相关。

Python编译器-Uzh似乎是用于为软件处理器开发软件的便捷工具箱。用于将基元和宏定义为目标语言功能的工具包允许在处理器的汇编语言中实现关键位置。本文讨论了堆栈体系结构处理器的编译器适应性要点。

而不是题词:

如果您将一只成年老鼠
并小心地握住,
将针塞入其中,
您将得到一只刺猬。

如果这只刺猬的
鼻子被塞住了,以免呼吸,那么
在更深的地方,扔进河里,
你会得到一个怒气。

如果这个r缩,
头放在虎钳中,
用力拉尾巴,
您将得到一条蛇。

如果已经这样,
准备好两把刀...
但是,他可能会死,
但是这个主意很好!


介绍


在许多情况下,实施测量仪器,研究设备时,最好使用可重构的FPGA / FPGA解决方案作为系统的主要核心。由于能够轻松,快速地更改工作逻辑,以及由于数据处理和控制信号的硬件加速,这种方法具有许多优势。

对于广泛的任务,例如数字信号处理,嵌入式控制系统,数据采集和分析系统,该方法已经证明了自己的方法,包括将一个由FPGA逻辑实现的解决方案模块组合到一个基于一个或多个关键流程和程序控制元素的解决方案中。几个软件处理器,用于常规管理和协调,以及实现与用户或外部设备/节点的交互。在这种情况下,使用软件处理器可使我们略微减少调试和验证系统控制算法或单个节点的交互算法所花费的时间。

典型的愿望清单


在这种情况下,软处理器通常不需要超高性能(因为更容易实现,因此我使用FPGA逻辑和硬件资源)。它们可以非常简单(从现代微控制器的角度来看-几乎是原始的),因为 他们无需复杂的中断系统即可完成工作,仅与某些节点或接口一起工作,而无需支持特定的命令系统。它们可以有很多,而它们每个只能执行一组特定的算法或子程序。根据当前任务的要求,软处理器的容量也可以是任何容量,包括一个字节的整数倍。

软处理器的典型目标是:

  • 命令系统的足够功能,可能针对任务进行了优化;
  • , .. ;
  • – , .

当然,软件处理器的问题是缺少针对它们的开发工具,尤其是如果其指令系统不是其流行的处理器内核之一的指令的子集时。在这种情况下,开发人员必须解决此问题。它的直接解决方案是为软件处理器创建汇编语言编译器。但是,在现代现实中,在Assembler中工作并不总是很方便,尤其是在项目开发过程中团队系统由于需求变化而发生变化时。因此,将上述要求添加到易于实现用于软处理器的高级语言编译器(HLV)的要求是合乎逻辑的。

源组件


堆栈处理器以很高的合规性满足这些要求,因为 无需寻址寄存器,命令的位深度可能很小。
它们的数据的位深度可以变化,并且与命令系统的位深度无关。作为编译过程中程序代码中间表示的事实上的硬件实现(尽管有一些警告),您可以以较低的人工成本将任何语言的语法转换为可执行代码,并将其翻译成可执行代码(尽管这是虚拟堆叠机或无上下文语法-存储自动机)。此外,对于堆栈处理器,Fort语言实际上是“本机”语言。为堆栈处理器实现Fort编译器的人工成本可与Assembler相比,在未来的程序实现中具有更大的灵活性和效率。

为了构建一种以接近实时的方式从智能传感器收集数据的系统,Fort处理器被选作软处理器的参考解决方案(所谓的参考设计),在[ 1 ]中进行了描述(以下简称为“参考设计”)。有时被其作者的昵称称为whiteTiger处理器)。

其主要特点:

  • 分离数据并返回堆栈
  • 哈佛内存组织架构(独立的程序和数据内存,包括地址空间);
  • 使用简单的并行总线扩展外围设备。
  • 处理器不使用管道,命令的执行是推挽式的:

    1. 获取命令和操作数;
    2. 执行命令并保存结果。

该处理器由程序代码的UART加载器补充,它使您可以更改可执行程序,而无需重新编译FPGA项目。

关于FPGA中块存储的配置,指令的容量设置为9位。数据的位深度设置为32位,但基本上可以是任意值。

处理器代码使用VHDL编写,无需使用任何特定的库,这使您可以在任何制造商的FPGA上使用此项目。

对于相对广泛的用途,降低“输入阈值”以及重用代码和应用代码开发,更方便的是切换到Fort以外的Java引擎(部分原因是矿山流程序员对这种语言的复杂性及其代码的可读性存在迷信和误解。 (顺便说一下,这项工作的一位作者对类C语言有类似的看法)。

基于多种因素,实验选择了Python语言(Python)以“绑定”软件处理器和Java语言引擎。这是一种高级通用编程语言,致力于提高开发人员的生产率和代码可读性,支持多种编程范例,包括结构,面向对象,功能,命令式和面向方面[ 2]。

新手开发者,其延伸MyHDL [ 34 ]是有趣,它允许硬件描述元件和结构在Python和将其转化为VHDL或Verilog代码。

不久前,Uzh编译器[ 5 ] 宣布-用于Zmey FPGA软件处理器的小型编译器(具有多线程支持的32位堆栈体系结构-如果您遵循版本/修改/验证链-Zmey是whiteTiger处理器的遥远后代)。
Uzh也是Python中的静态编译子集的基础上,看好raddsl工具箱[(用于快速创建DSL的编译器原型的工具集)67 ]。

因此,影响工作方向选择的因素可以大致表述为:

  • 对降低FPGA上的设备和系统新手开发人员的“入门门槛”的工具的兴趣(语法上,Python对于初学者而言并不像VHDL那样“吓人”);
  • 在项目中争取和谐和单一风格(理论上可以用Python描述软件处理器所需的硬件模块和软件);
  • 随机巧合。

微小,“几乎”毫无意义的细微差别


Zmey处理器的源代码未公开,但是提供了其操作原理和某些体系结构功能的描述。尽管它也是可堆叠的,但与whiteTiger处理器有许多关键区别:

  • 堆栈是软件-即 用指针表示并放置在数据存储器的不同地址处;
  • , - ;
  • ;
  • , .

因此,Uzh编译器将这些功能考虑在内。编译器接受Python代码并在输出处生成启动流,以启动程序存储器和处理器数据存储器,关键是在编译阶段所有语言功能都可用。

要安装Uzh编译器,只需下载其归档文件并将其解压缩到任何方便的文件夹中(最好遵循针对专用软件的一般建议-避免路径包含西里尔字母和空格)。您还需要下载raddsl工具包并将其解压缩到编译器的主文件夹中。

编译器测试文件夹包含用于软处理器的程序的示例; src文件夹包含编译器元素的源文本。为方便起见,最好使用以下内容创建一个小的批处理文件(扩展名为.cmd):,c.py C:\D\My_Docs\Documents\uzh-master\tests\abc.py 其中abc.py是带有用于软处理器的程序的文件名。

蛇咬尾巴或搭铁和软件


为了使Uzh适应whiteTiger处理器,将需要进行一些更改,并且必须对处理器本身进行一些更正。

幸运的是,编译器中没有太多要调整的地方。主要的“与硬件相关的”文件:

  • asm.py-汇编程序和数字的形成(文字);
  • gen.py-低级代码生成规则(函数,变量,转换和条件);
  • stream.py-形成引导流;
  • macro.py-宏定义,实际上-具有特定于硬件的功能的基本语言的扩展。

在原始的白色老虎处理器设计中,UART加载器仅初始化程序存储器。引导加载程序算法很简单,但是已经建立并且可靠:

  • 当接收到某个控制字节时,加载器在处理器复位的内部线路上设置活动级别;
  • 第二个字节命令复位存储器地址计数器;
  • 然后从最年轻的字母开始,跟随一个传输单词的笔记本序列,再加上一个笔记本编号;
  • 在带有打包笔记本的每个字节之后,紧接着是一对控制字节,第一个控制字节在存储器写允许行上设置活动级别,第二个将其重置;
  • 完成打包笔记本的顺序后,复位行上的活动电平将被控制字节删除。

由于编译器还使用数据存储器,因此有必要修改加载程序,使其也可以初始化数据存储器。

由于数据存储器包含在处理器内核的逻辑中,因此有必要多路复用其数据线和控制线。为此,引入了其他信号DataDinBtemp,LoaderAddrB,DataWeBtemp-内存中端口的数据,地址和写入权限。

现在,引导程序代码如下所示:

uart_unit: entity work.uart
--uart_unit: entity uart
  Generic map(
    ClkFreq => 50_000_000,
    Baudrate => 115200)
  port map(
    clk => clk,
    rxd => rx,
    txd => tx,
    dout => receivedByte,
    received => received,
    din => transmitByte,
    transmit => transmit);
    
process(clk)
begin
  if rising_edge(clk) then
    if received = '1' then
      case conv_integer(receivedByte) is
      -- 0-F   - 0-3 bits
        when 0 to 15 => CodeDinA(3 downto 0) <= receivedByte(3 downto 0);
		                  DataDinBtemp(3 downto 0) <= receivedByte(3 downto 0);
      -- 10-1F -4-7bits
        when 16 to 31 => CodeDinA(7 downto 4) <= receivedByte(3 downto 0);
		                   DataDinBtemp(7 downto 4) <= receivedByte(3 downto 0); 
      -- 20-2F -8bit 
        when 32 to 47 => CodeDinA(8) <= receivedByte(0);
	                   DataDinBtemp(11 downto 8) <= receivedByte(3 downto 0);
	  when 48 to 63 => DataDinBtemp(15 downto 12) <= receivedByte(3 downto 0);
	  when 64 to 79 => DataDinBtemp(19 downto 16) <= receivedByte(3 downto 0);
	  when 80 to 95 => DataDinBtemp(23 downto 20) <= receivedByte(3 downto 0);
	  when 96 to 111 => DataDinBtemp(27 downto 24) <= receivedByte(3 downto 0);
        when 112 to 127 => DataDinBtemp(31 downto 28) <= receivedByte(3 downto 0);

      -- F0 addr=0
        when 240 => CodeAddrA <= (others => '0');
      -- F1 - WE=1
        when 241 => CodeWeA <= '1';
      -- F2 WE=0 addr++
        when 242 => CodeWeA <= '0'; CodeAddrA <= CodeAddrA + 1;
      -- F3 RESET=1
        when 243 => int_reset <= '1';
      -- F4 RESET=0
        when 244 => int_reset <= '0';

      -- F5 addr=0
        when 245 => LoaderAddrB <= (others => '0');
      -- F6 - WE=1
        when 246 => DataWeBtemp <= '1';
      -- F7 WE=0 addr++
        when 247 => DataWeBtemp <= '0'; LoaderAddrB <= LoaderAddrB + 1;
		  
		  
        when others => null;
      end case;
    end if;
  end if;
end process;

---- end of loader


在活动复位级别下,DataDinBtemp,LoaderAddrB,DataWeBtemp信号连接到相应的数据存储端口。

if reset = '1' or int_reset = '1' then
      DSAddrA <= (others => '0');      
      
      RSAddrA <= (others => '0');
      RSAddrB <= (others => '0');
      RSWeA <= '0';
      
      DataAddrB <= LoaderAddrB;
		DataDinB<=DataDinBtemp;
		DataWeB<=DataWeBtemp;
      DataWeA <= '0';

根据引导加载程序算法,有必要修改stream.py模块。现在,它具有两个功能。第一个函数-get_val() -将输入字分割为所需数量的四分位数。因此,对于whiteTiger处理器的9位指令,它们将被转换为三个四元组的组,并被转换为八个四元组的序列中的32位数据。第二个函数make()直接形成引导程序。
流模块的最终形式:

def get_val(x, by_4):
  r = []
  for i in range(by_4):
    r.append((x & 0xf) | (i << 4))
    x >>= 4
  return r

def make(code, data, core=0):
  #        0  
  stream = [243,245] 
  for x in data:
    #    32- 
    #         
    stream += get_val(x, 8) + [246, 247]
  #       0
  stream += [240]
  for x in code:
    #    9-  
    #         
    stream += get_val(x, 3) + [241, 242]
  #  
  stream.append(244)

  return bytearray(stream)


编译器中的以下更改将影响asm.py模块,该模块描述了处理器的命令系统(已编写命令助记符和命令操作码)以及表示/编译数值-文字的方式。

命令打包成字典,而lite()函数负责文字。如果命令系统的一切都很简单-助记符列表和相应的操作码只是在变化,那么文字的情况会有些不同。 Zmey处理器具有8位指令,并且有许多用于处理文字的专用指令。在whiteTiger中,第9位指示操作码是命令还是数字的一部分。

如果单词的最高(第9位)为1,则操作码将被解释为数字-例如,四个连续的带有数字符号的操作码将形成一个32位数字。数字结尾的标志是命令操作码的存在-为了确定性和确保一致性,数字确定的结尾是NOP命令的操作码(“无操作”)。

结果,修改后的lit()函数如下所示:


def lit(x):
  x &= 0xffffffff
  r = [] 
  if (x>>24) & 255 :
    r.append(int((x>>24) & 255) | 256)
  if (x>>16) & 255:
    r.append(int((x>>16) & 255) | 256)
  if (x>>8) & 255:
    r.append(int((x>>8) & 255) | 256)
  r.append(int(x & 255) | 256)
  r += asm("NOP")
  return list(r)


主要和最重要的更改/定义在gen.py模块中。此模块定义了在汇编器级别上工作/执行高级代码的基本逻辑:

  • 有条件的和无条件的跳跃;
  • 调用函数并将参数传递给它们;
  • 从函数返回并返回结果;
  • 调整程序存储器,数据存储器和堆栈的大小;
  • 处理器启动时的动作顺序。

为了支持Java,处理器必须能够任意处理内存和指针,并具有用于存储局部变量函数的内存区域。

在Zmey处理器中,返回栈用于处理局部变量和函数自变量-函数自变量被传递给它,并且在进一步的工作中,它们通过返回栈的指针寄存器进行访问(读取,向上/向下修改,在指针地址处读取)。由于堆栈物理上位于数据存储器中,因此此类操作实质上可以简单地归结为存储器操作,并且全局变量位于同一存储器内。

在whiteTiger中,返回堆栈和数据堆栈是专用的硬件堆栈,具有其地址空间,并且没有堆栈指针指令。因此,需要通过数据存储器来组织将参数传递给函数并与局部变量一起使用的操作。增加数据堆栈的容量并返回以在其中存储相对较大的数据阵列没有太大意义;拥有稍大的数据存储器则更合逻辑。

为了使用局部变量,添加了一个专用的LocalReg寄存器,其任务是存储指向分配给局部变量(一种堆)的内存区域的指针。还添加了使用它的操作(cpu.vhd文件-命令定义区域):


          -- group 1; pop 0; push 1;
          when cmdLOCAL => DSDinA <= LocalReg;
			 when cmdLOCALadd => DSDinA <= LocalReg; LocalReg <= LocalReg+1;
			 when cmdLOCALsubb => DSDinA <= LocalReg; LocalReg <= LocalReg-1;
          -- group 2; pop 1; push 0;
          when cmdSETLOCAL => LocalReg <= DSDinA;

LOCAL-将LocalReg指针的当前值返回到数据堆栈;
SETLOCAL-设置从数据堆栈接收的新指针值;
LOCALadd-将指针的当前值保留在数据堆栈上,并将其递增1;否则,该值为0。
LOCALsubb-将指针的当前值保留在数据堆栈上,并将其当前值减
1。LOCALadd和LOCALsubb被添加以减少传递函数参数的操作期间的滴答声数量,反之亦然。

与原始的whiteTiger不同,数据存储器的连接稍有变化-现在,通过数据堆栈的第一个单元的输出不断寻址In内存端口,将数据堆栈的第二个单元的输出馈送到其输入:

-- ++
DataAddrB <= DSDoutA(DataAddrB'range);
DataDinB <= DSDoutB;

执行STORE和FETCH命令的逻辑也已稍作纠正-FETCH在数据堆栈顶部的内存中接收端口的输出值,而STORE仅控制端口B的写使能信号:

-- group 3; pop 1; push 1;
          when cmdFETCH => DSDinA <= DataDoutB;
          when cmdSTORE =>            
            DataWeB <= '1';

作为培训的一部分,以及对底层(以及Fort语言的编译器级别)的某些硬件对循环的支持,在whiteTiger核心中添加了一个循环计数器堆栈(操作类似于声明数据和返回堆栈时的操作):

--  
type TCycleStack is array(0 to LocalSize-1) of DataSignal;
signal CycleStack: TCycleStack;
signal CSAddrA, CSAddrB: StackAddrSignal;
signal CSDoutA, CSDoutB: DataSignal;
signal CSDinA, CSDinB: DataSignal;
signal CSWeA, CSWeB: std_logic;
--  
process(clk)
begin
  if rising_edge(clk) then
    if CSWeA = '1' then
      CycleStack(conv_integer(CSAddrA)) <= CSDinA;
      CSDoutA <= CSDinA;
    else
      CSDoutA <= CycleStack(conv_integer(CSAddrA));
    end if;
  end if;
end process;


循环计数器命令已添加。

DO-将循环的迭代次数从数据堆栈移至计数器堆栈,并将指令计数器的递增值放在返回堆栈上。

LOOP-检查计数器归零,如果未达到,则将计数器堆栈的顶部元素递减,执行到返回堆栈顶部地址的转换。如果计数器堆栈的顶部为零,则顶部元素被复位,从复位堆栈顶部到循环开始的返回地址也将被复位。


	when cmdDO => -- DO - 
               RSAddrA <= RSAddrA + 1; -- 
               RSDinA <= ip + 1;
               RSWeA <= '1';
				
               CSAddrA <= CSAddrA + 1; --
         		CSDinA <= DSDoutA;
 		         CSWeA <= '1';
		         DSAddrA <= DSAddrA - 1; --
		         ip <= ip + 1;	-- 

      when cmdLOOP => --            
           if conv_integer(CSDoutA) = 0 then
	          ip <= ip + 1;	-- 
		         RSAddrA <= RSAddrA - 1; -- 
		         CSAddrA <= CSAddrA - 1; -- 
            else
		         CSDinA <= CSDoutA - 1;
		         CSWeA <= '1';
		         ip <= RSDoutA(ip'range);
            end if;
			 

现在,您可以开始修改gen.py模块的代码。

* _SIZE变量不需要注释,仅需要替换处理器核心项目中指定的值。

STUB列表是一个临时存根,用于为转换地址创建一个位置,然后用编译器填充它们(当前值对应于代码存储器的24位地址空间)。

STARTUP列表-设置内核在复位后执行的操作顺序-在这种情况下,局部变量的内存的起始地址设置为900,并过渡到起点(如果不进行任何更改,则应用程序中的起点/入口点将在数据存储器地址中写入编译器2):

STARTUP = asm("""
900  SETLOCAL
2 NOP FETCH JMP
""")

func()的定义规定了调用函数时执行的操作,即,将函数参数传递到局部变量区域,为函数自身的局部变量分配内存。

@act
def func(t, X):
  t.c.entry = t.c.globs[X]
  t.c.entry["offs"] = len(t.c.code) # - 1
  args = t.c.entry["args"]
  temps_size = len(t.c.entry["locs"]) - args
#      
  t.out = asm("LOCALadd STORE " * args)
  if temps_size:
#      
    t.out += asm("LOCAL %d PLUS SETLOCAL" % temps_size)
  return True

Epilog()定义了从函数返回时的操作-释放临时变量的内存,返回到调用点。

def epilog(t, X):
  locs_size = len(t.c.entry["locs"])
#    
  t.out = asm("RET")
  if locs_size:
#    ()  
    t.out = asm("LOCAL %d MINUS SETLOCAL" % locs_size) + t.out
  return True


使用变量的操作是通过它们的地址来完成的,其关键定义是push_local(),它将“高级”变量的地址保留在数据堆栈上。

def push_local(t, X):
#          
#  
  t.out = asm("LOCAL %d MINUS" % get_loc_offset(t, X))
  return True

以下要点是条件转换和无条件转换。whiteTiger处理器中的条件跳转将检查数据堆栈的第二个元素是否为0,如果满足条件,则跳转到堆栈顶部的地址。无条件跳转只是将指令计数器的值设置为堆栈顶部的值。

@act
def goto_if_0(t, X):
  push_label(t, X)
  t.out += asm("IF")
  return True

@act
def goto(t, X):
  push_label(t, X)
  t.out += asm("JMP")
  return True


以下两个定义指定了移位操作-仅在较低级别上应用了循环(这将使代码的大小有所增加-在最初,编译器只是将所需数量的基本移位操作放在一行中。

@act
def shl_const(t, X):
  t.out = asm("%d DO SHL LOOP" %(X-1))
  return True

@act
def shr_const(t, X):
  t.out = asm("%d DO SHR LOOP" %(X-1))
  return True

底层的编译器主要定义是一组语言操作和内存使用规则:

stmt = rule(alt(
  seq(Push(Int(X)), to(lambda v: asm("%d" % v.X))),
  seq(Push(Local(X)), push_local),
  seq(Push(Global(X)), push_global),
  seq(Load(), to(lambda v: asm("NOP FETCH"))),
  seq(Store(), to(lambda v: asm("STORE"))),
  seq(Call(), to(lambda v: asm("CALL"))),
  seq(BinOp("+"), to(lambda v: asm("PLUS"))),
  seq(BinOp("-"), to(lambda v: asm("MINUS"))),
  seq(BinOp("&"), to(lambda v: asm("AND"))),
  seq(BinOp("|"), to(lambda v: asm("OR"))),
  seq(BinOp("^"), to(lambda v: asm("XOR"))),
  seq(BinOp("*"), to(lambda v: asm("MUL"))),
  seq(BinOp("<"), to(lambda v: asm("LESS"))),
  seq(BinOp(">"), to(lambda v: asm("GREATER"))),
  seq(BinOp("=="), to(lambda v: asm("EQUAL"))),
  seq(BinOp("~"), to(lambda v: asm("NOT"))),
  seq(ShlConst(X), shl_const),
  seq(ShrConst(X), shr_const),
  seq(Func(X), func),
  seq(Label(X), label),
  seq(Return(X), epilog),
  seq(GotoIf0(X), goto_if_0),
  seq(Goto(X), goto),
  seq(Nop(), to(lambda v: asm("NOP"))),
  seq(Asm(X), to(lambda v: asm(v.X)))
))

macro.py模块允许您使用目标处理器的汇编程序中的宏定义来“扩展”目标语言的词典。对于Java编译器,macro.py中的定义与该语言的“本机”运算符和函数没有区别。因此,例如,在原始编译器中,定义了外部端口中值的I / O函数。添加了具有存储器和局部变量的操作的测试序列以及一个延时操作。

@macro(1,0)
def testasm(c,x):
  return Asm("1 1 OUTPORT 0 1 OUTPORT 11 10 STORE 10 FETCH 1 OUTPORT  15 100 STORE 100  FETCH 1 OUTPORT")

@macro(1,0)
def testlocal(c,x):
   return Asm("1 100 STORE 2 101 STORE 100 SETLOCAL LOCAL NOP FETCH 1 OUTPORT LOCAL 1 PLUS NOP FETCH 1 OUTPORT")

@prim(1, 0)
def delay(c, val):
  return [val, Asm("DO LOOP")]


测试中


我们处理器的一个小型测试高级程序包含用于计算阶乘的函数的定义,以及实现无限循环中从1到7到端口的阶乘值串行输出的主要函数。

def fact(n):
  r = 1
  while n > 1:
    r *= n
    n -= 1
  return r


def main():
  n=1
  while True:
     digital_write(1, fact(n))
     delay(10)
     n=(n+1)&0x7


例如,可以通过一个简单的脚本或从命令行按以下顺序 启动它进行编译:结果,将生成一个启动文件stream.bin,该文件可以通过串行端口(在现代情况下,通过转换器提供的任何虚拟串行端口)传输到FPGA的处理器内核中。 USB-UART接口)。结果,程序占用了146个字(9位)的程序存储器,而数据存储器中的3个字。
c.py C:\D\My_Docs\Documents\uzh-master\tests\fact2.py




结论


通常,Uzh编译器似乎是用于为软件处理器开发软件的简便工具包。至少就程序员的可用性而言,它是汇编程序的绝佳替代品。用于将基元和宏定义为目标语言功能的工具包允许在处理器的汇编语言中实现关键位置。对于堆栈体系结构处理器,编译器适配过程不会太复杂和冗长。我们可以说,只有在编译器的源代码可用性有所帮助的情况下-编译器的关键部分正在发生变化。

FPGA Altera Cyclone V系列的处理器综合结果(32位容量,4K字的程序存储器和1K RAM)得出以下结果:

Family	Cyclone V
Device	5CEBA4F23C7
Logic utilization (in ALMs)	694 / 18,480 ( 4 % )
Total registers	447
Total pins	83 / 224 ( 37 % )
Total virtual pins	0
Total block memory bits	72,192 / 3,153,920 ( 2 % )
Total DSP Blocks	2 / 66 ( 3 % )

文献

  1. VHDL上的Forth处理器// m.habr.com/zh/post/149686
  2. Python-Wikipedia // en.wikipedia.org/wiki/Python
  3. 我们开始在Python上进行FPGA _ Habr // m.habr.com/en/post/439638
  4. MyHDL // www.myhdl.org
  5. github-true-grue_uzh_ Uzh编译器// github.com/true-grue/uzh
  6. github-true-grue_raddsl_用于DSL编译器快速原型制作的工具// github.com/true-grue/raddsl
  7. sovietov.com/txt/dsl_python_conf.pdf

作者感谢Zmey软件处理器和Uzh编译器的开发人员的咨询和耐心。

All Articles