A Golden Age of Hardware Description Languages: Applying Programming Language Techniques to Improve译

因最近关注HDL比较多,正好遇到了此篇文章,现基于百度翻译如下,如有谬误或不通之处,请自行查阅原文:

作者:
Lenny Truong,Pat Hanrahan
Stanford University

Abstract

著名专家宣称,计算机体系结构的黄金时代即将到来。在这个时代,架构创新的速度将直接与使用的硬件描述语言的设计和实现联系在一起。因此,编程语言社区站在通往这个新黄金时代的关键道路上。这意味着我们也处在硬件描述语言黄金时代的尖端。在本文中,我们讨论了对硬件描述语言设计、编译器和形式化方法感兴趣的研究人员所面临的智力挑战。主要主题是识别出如何应用编程语言技术解决硬件设计生产力问题的机会。然后,我们提出了一个多语言系统的愿景,该系统为开发解决这些智力问题提供了一个框架。这一愿景是基于将元编程主机语言与核心嵌入式硬件描述语言相结合,以此作为研究和开发领域特定语言的基础。该系统设计的核心是基于抽象的核心语言,该抽象为用任何语言描述的硬件组件的组合提供了通用机制。

1 Introduction

图灵奖得主John Hennessy和David Patterson最近宣布,我们正处在计算机体系结构新黄金时代的风口浪尖上[29,30]。当前硅制造业的发展趋势预示着摩尔定律和Dennard scaling的终结。这与通用处理器设计中固有的低效性相结合,表明计算机体系结构的新创新将来自于特定领域体系结构的设计。最近专用加速器的激增,如苹果的A12神经引擎和谷歌的张量处理单元TPU,支持了硬件界正在向专用芯片设计过渡的想法。这一转变标志着一个新的黄金时代,因为研究人员有机会开发完全不同的体系结构,而不是对现有处理器设计进行增量改进。

特定领域的芯片必然以较小的市场为目标,这意味着设计团队将变得更小,并且需要更多的工具来提高生产效率。这表明我们也正处于硬件描述语言(HDL)的黄金时代,因为硬件设计者正在积极寻求能够显著减少设计时间和成本的全新技术。设计生产力的一个主要障碍在于硬件生态系统是一个单一文化,由少数制造商的一些芯片设计组成。硬件社区转向一个多样化的生态系统是非常重要的,该生态系统由易于访问的IP块组成,这些IP块可用于构建新的芯片设计。这一转变的基础将是HDL的进步,其促进了硬件库的扩散。

如何促进重用、正确性和性能的HDL抽象的开发代表了HDL在这个新黄金时代的主要挑战。幸运的是,编程语言(PL)社区在开发解决这些问题的技术方面有着丰富的成功历史。HDL研究人员已经开始通过应用标准软件编程语言技术(如元编程、多态性和抽象数据类型)来解决重用问题[4,11]。显然,HDL研究人员将从他们的软件语言同行所学到的经验中获益匪浅。

本文指出了程序设计语言与硬件交叉的三个问题域:语言设计、编译器基础结构和形式化方法。对于那些不熟悉硬件设计过程或HDL的人,第2节介绍了理解第3节中讨论的智力挑战所需的基本概念。第4节介绍了一个用于构建硬件的多语言系统的远景,该系统旨在解决这些智力挑战。在这个即将到来的HDL黄金时代,对编程语言和硬件感兴趣是一个激动人心的时刻(it is an exciting time to be interested in programming languages and hardware.)。

2 Background

硬件描述语言(HDL)是一种编程语言的实例,它被设计用来提供描述电路的抽象。本文将着重讨论数字硬件,其中电路被描述为在离散二进制信号上的逻辑操作。数字硬件可进一步分为两类:同步和异步。在同步电路中,状态变化由时钟信号同步。与之相反的是,异步电路可以包含随时变化的状态元素。大多数现代数字设计都是同步的,但对效率的日益增长的需求重新引起了人们对异步设计或混合模型(如全局异步、局部同步)的兴趣[58]。对于同步和异步设计,如果一个数字HDL均可以表示,则其被定义为表示完整的。
HDL_1图1 由带状态的组合逻辑构成的时序逻辑电路的抽象描述。请注意,输出可能依赖于输入,这意味着电路可以描述一个Mealey 机[43]。根据存储状态所选择的机制,电路可以是同步的,也可以是异步的。详见第2.1节。

2.1 数字化设计

在数字电路理论中,组合逻辑指的是输出是输入的纯函数和全函数的电路。相反,时序逻辑指的是输出依赖于过去输入序列的电路。图1描述了由状态和组合逻辑电路来构造时序逻辑电路的规范设计模式。时序逻辑电路用于实现有限状态机(FSM),这是构建数字系统的基本组成部分。

在硬件设计的背景下讨论FSM时,认识到Mealey[43]和Moore[45]机之间的区别是很重要的。对于Mealey机器,电路的输出是状态和输入的函数,而对于Moore机器,电路的输出完全依赖于状态。这些类型的FSM之间的差异在硬件上比在软件上更明显,因为它们表现出不同的时序特性。当使用寄存器存储状态时,Moore机可以被视为一个纯粹的同步实体,其中状态和输出值的更改由时钟触发,而Mealey机可以表现出异步行为,其中输出值立即响应输入值的更改。一个表达完整的HDL将能够描述和组成Mealey和Moore机。

2.2 验证日志

Verilog语言是当今实践中使用的主要HDL语言[23]。该语言最初是开发用于商业验证和仿真产品[24],后来被用作逻辑综合的基础。因此,语言的语义是根据作为软件程序执行的硬件模拟来定义的(the semantics of the language are defined in terms of a hardware simulation being executed as a software program)[57]。该语言的设计直接受到C语言的启发,展示了许多相同的特性,包括预处理器、控制流和操作符。与C一样,Verilog已经成为HDL生态系统的通用语言,并被用作设计工具的通用交换格式。

Verilog语义的核心是基于模块抽象,它与软件语言的功能抽象有许多相似之处。模块有一个接口和一个定义。接口是一组类型化端口。端口类似于函数参数或返回值,表示用于使用或生成数据的命名实体。定义是一组语句,这些语句使用各种语言特性(如连接和模块实例操作符)来描述模块行为。Verilog设计由层次化的模块组成,这些模块使用数据流执行模型进行仿真。

图2显示了用Verilog编写的边沿检测器FSM。

module edge_detector(input in, output out, input clk);
	localparam A=0, B=1, C=2;
	
	reg [1:0] state, // Current state 
			  nextState; // Next state
			  
	always @(posedge clk) begin 
		if (reset) begin 
			state <= A; // Initial state
		end else begin 
			state <= nextState;
		end
	end

	always @(*) begin 
		nextState = state; 
		out = 0;
		case (state)
		A : if (in) nextState = C; 
			else nextState = B;
		B : if (in) begin 
				out = 1; nextState = C; 
			end
		C : if (~in) begin 
				out = 1; nextState = B; 
				end
		default : begin 
				out = 1'bX; nextState = 3'bX; 
		end 
		endcase
	end
endmodule

图2 一种源自华盛顿大学CSE370课程材料的边沿检测FSM的Verilog实现[20]。该电路有两个输入和一个输出,设计成一个Mealey机,如果in的电流值与in的先前值相反(即输入从1变为0或从0变为1),则输出为1。第1行声明模块名和接口。这些端口的隐式宽度为1位,并且具有方向输入或输出。第2行声明了一组用于抽象FSM状态编码的常量。第4行和第5行声明了保存当前和下一个状态的变量。第7-13行描述Verilog always块中的状态更新逻辑。这段代码定义了发生posedge clk事件时要运行的过程。也就是说,在时钟上升沿,更新或重置状态变量。第15-34行定义了另一个对任何输入信号的变化敏感的always块,用@(*)表示。这意味着,如果任何输入值发生更改,将触发此代码块。该块将用于计算输出和下一状态值的组合逻辑编码为输入和当前状态值的函数。因为第二个always块对任何输入更改都很敏感,所以语义是异步定义的。这与第一个always块形成对比,后者通过仅在时钟的上升沿执行来强制状态更新为同步。在第30行和第31行,out和nextState的值被赋值X,以明确表示它们未定义,可以是任何值。详见第2.2节。

1 acc1 :: Stream Word -> Stream Word
2 acc1 in = out
3 	where
4 		out = ( delay out 0) + in
5
6-- input -> current state -> (new state , output )
7 acc2 :: Word -> Word -> (Word , Word )
8 acc2 in s = (s’, out)
9 	where
10 		out = s + in
11 		s’ = out

图3 使用Haskell嵌入式HDL编码状态的两种机制的示例,改编自Clash文档[39]。这两个函数都描述了一个累加器体系结构,它存储了一段时间内输入值的运行计数。函数acc1显示了第一种方法,它基于带有delay操作符的流数据结构。delay操作符将输入流的值偏移一个周期进行返回。delay的第二个参数用于指定流的第一个值。函数acc2使用不同的方法,其中当前状态作为参数传递,下一个状态作为输出返回。详见第2.3节。

2.3 功能性HDL

HDL开发在函数式语言社区有着悠久的传统[46]。Functional HDL利用了纯函数可以用来建模组合逻辑的思想。这些语言面临的基本问题是集成时间和状态的概念,以便能够描述时序逻辑。

µFP[55]和Daisy[35]都引入了一种基于反应式编程的技术,其中流数据结构用于描述输出可依赖于输入历史的电路。µFP拓展了FP,使用递归定义的µ,接受一个函数并产生一个具有内部状态的新函数。µ 运算符的本质是指它提供状态的当前值作为函数的输入,并使用函数的输出设置状态的下一个值。Daisy使用了一种不同的方法,通过递归方程对sequential逻辑进行建模。这两种方法都需要开发一种新的语言来实现它们的想法。Clash[39]的设计者认识到Haskell的惰性评估可以用来构造无限流,这表明它可以作为嵌入式HDL的宿主。图3显示了Haskell的语义如何支持时序逻辑电路的描述。

应用于功能性HDL的一个有趣的技术是使用组合词来描述电路结构。Hydra[50]表明,递归的、基于流的抽象使得能够使用高阶函数来捕获结构模式。Lava[11]扩展了递归数据类型的使用,能够描述一般的电路网络,而不仅仅是树状结构。这种技术通过将电路描述为组件的规则模式,为代码重用提供了强大的工具。在实践中,这种方法被证明在应用于电路布局问题时特别有用[56]。

2.4 术语重写系统

另一系列的工作[32]探索了术语重写系统(TRS)[52]在硬件描述中的应用。在这些系统中,电路被描述为一组重写规则,这些规则应用于输入和状态值以产生输出和下一个输出状态值。TRS的一个重要特性是对硬件中固有的不确定性和并发性进行建模。例如,当两个规则匹配相同的输入数据并尝试更新相同的状态元素时,可能会发生冲突。开发用于检测和仲裁冲突的方案是这些系统面临的主要智力挑战。图4显示了用Bluespec[47]编写的同步计数器,这是一种基于TRS建立的HDL。

1 module mkCounter ( Counter );
2 	Reg #( Bit #(8)) value <- mkReg (0);
3
4	method Bit #(8) read ();
5 		return value ;
6 	endmethod
7
8	method Action load (Bit #(8) newval );
9 		value <= newval ;
10 	endmethod
11
12 	method Action increment ();
13 		value <= value + 1;
14 	endmethod
15 endmodule

图4 同步计数器的实现改编自Bluespec教程[12],省略了模块接口规范。第2行声明一个名为value的8位寄存器。第4-14行定义了read、load和increment方法的实现,这些方法定义了模块的行为。注意,编译器必须处理load和increment-on-value之间的数据竞争。详见第2.4节。

2.5 高层次综合

高层次综合(HLS)是一种广泛定义为将通用软件程序编译为硬件的技术[65]。本文将避免使用HLS这个术语,因为何为高层次还是模糊不清的。例如,最近的一项调查使用C语言编写的基准来评估HLS工具[46]。然而,PL社区将考虑C是一种低级语言。相反,本文将使用虚拟机抽象的概念来包含作为HLS系统输入的语言。基于虚拟机抽象的语言提供了无限资源的概念,例如无限寄存器空间。第3.1.3节对此进行了更详细的讨论。

通用编程语言的硬件编译器依赖于一种策略,将一个在时间和空间上可能是无限的程序映射到一组有限的资源中。通常,这涉及到探索在空间或时间上调度计算之间的权衡。如果编译器可以在某些计算中确定并行性,则可以将此逻辑映射到并发执行的硬件模块中。然而,数据依赖性、有限的资源和次优的成本模型使大型应用程序的任务复杂化。编译器必须使用启发式将计算安排到时间维度,并插入必要的逻辑来编排计算的顺序。图5显示了在SystemC[22]中实现的同步计数器,SystemC是用于HLS的C语言的一个子集

1 SC_MODULE ( counter ) {
2 	sc_in_clk clock ;
3 	sc_in <bool > reset ;
4 	sc_out < sc_uint <4> > counter_out ;
5
6	sc_uint <4> count ;
7
8	void incr_count () {
9 		if ( reset . read () == 1) {
10 			count = 0;
11 			counter_out . write ( count );
12 		} else {
13 			count = count + 1;
14 			counter_out . write ( count );
15 		}
16 }
17
18 	SC_CTOR ( counter ) {
19 		SC_METHOD ( incr_count );
20 		sensitive << reset ;
21 		sensitive << clock .pos ();
22 	}
23 };

图5 改编自[1]的SystemC中定义的4位计数器示例。第2-4行声明模块的接口。第6行声明了一个内部状态变量。第8-16行定义了一个incr_count方法,该方法使用SystemC数据类型实现计数器的行为。请注意,输入端口是使用read方法读取的,输出是使用write方法写入的。定义主体的其余部分被解释为普通的C代码。第18-22行定义计数器对象的构造函数,主要负责定义模块对复位输入的灵敏度以及时钟输入的正边沿。详见第2.5节。

3 智力挑战

本节将HDL研究的关注点分为三个智能领域:语言设计、编译器基础结构和形式化方法。这些领域中的每一个都代表了更广泛的PL社区感兴趣的更一般的研究领域的子集。

3.1 语言设计

编程语言设计的一般原则是围绕抽象的发展。语言设计者将采用抽象,使用户可以忽略程序的某些细节。设计良好的抽象使程序的开发和维护更容易。在某些情况下,例如在领域特定语言(DSL)中,抽象还可以作为开发编译器优化的基础。在这个即将到来的黄金时代,HDL设计者面临的主要挑战将是设计和编写能够实现代码重用、提高程序正确性的抽象,以及可以用来构造从编译器中产生高质量结果的设计。

在现代HDL设计中有三个主要的抽象层次。最低层次是电路抽象,其中硬件被建模为连接组件的图形。下一个层次是寄存器传输抽象,其中硬件被描述为寄存器之间数据流的计算。最高级别是虚拟机抽象,其中硬件被建模为抽象机的一组指令。许多HDL包含多个层次的抽象。例如,Verilog语言是基于电路抽象的,但也提供了使用寄存器传输抽象描述硬件的各种工具。

3.1.1 电路抽象

在电路抽象中,硬件被描述为连接元件的图形。抽象包括三个基本概念:电路、端口和导线。电路有接口和定义。接口由一组端口组成。端口是用于使用或生成数据的命名实体。定义包含一组回路实例和导线。一根线连接两个端口。在硬件社区中,基于电路抽象的语言特性被描述为结构化的。例如,用结构化Verilog编写的设计将只使用语言特性来定义、实例化和连接Verilog模块。纯粹的结构设计称为网表。

目前使用的主要结构HDL是Verilog。Chisel[4]和Magma[27]是一个新兴的结构语言子类,称为硬件构造语言。 这些语言将电路抽象嵌入到通用编程语言中,该语言为元编程电路定义提供了一种机制。这种方法比Verilog具有明显的优势;将与参数化和代码生成相关的特性移动到宿主语言,简化了HDL的精确规范。

从理论上讲,一个纯结构化的HDL足以表达任何真实世界的数字硬件设计。这是因为制造硬件的物理结果总是由连接的子组件组成的组件,一直递归到晶体管。基于这一事实,我们假设电路抽象是所有其他HDL抽象可以构造的基本原语。注意,抽象对于电路的行为是同步的还是异步的是不可知的,这表明它是表达完整的。

电路抽象的主要挑战是确定两个端口之间的连接在设计的预期行为方面是否语义正确。大多数HDL都将方向的概念附加到端口上,这使得类型系统能够检查只有输出才能连接到输入。一个有趣的研究方向是提高电路端口类型的表达能力。理想情况下,这些类型能够捕获用于在两个组件之间通信的协议的语义。第3.3.2节详细讨论了如何使用会话类型来解决此问题。

电路抽象的一个有趣的特性是,虽然它是基于硬件设计的低级细节,但它可以用于在设计层次结构的任何级别组成黑盒模块。这使得它成为开发硬件库的有力基础。如第2.3节所讨论的,具有电路抽象的功能性HDL可以利用组合模式来构建可重用的电路结构。进一步研究能够构建基于电路抽象的硬件库的语言设施,将是HDL这一新黄金时代的重要组成部分。

3.1.2 寄存器传输抽象

寄存器传输抽象将硬件建模为寄存器间数据流的计算。寄存器被定义为基于时钟信号更新其值的primitive数据存储元素。由于寄存器语义本质上与时钟有关,因此这种抽象涉及同步数字电路的描述。但是,需要注意的是,这个抽象可以由其他抽象组成,用于描述异步逻辑。在硬件社区中,使用寄存器传输抽象的语言被描述为寄存器传输级(RTL)语言。

包含寄存器概念的结构化HDL提供寄存器传输抽象;使用电路实例和连接描述寄存器间数据流的计算。然而,寄存器传输抽象层包含了更广泛的概念集,如函数和运算符。在实践中,大多数HDL通过扩展电路定义的概念来包含表达式、语句和过程等构造,将寄存器传输抽象与电路抽象结合起来。这种技术通过消除显式定义、实例和连接寄存器电路的需要,提高了抽象级别。相反,寄存器被视为语言原语,其行为类似于标准软件编程语言中的变量。

RTL语言设计的基本问题是语域概念抽象语义的精确选择。例如,verilog always块提供了一个过程抽象,用于描述组件的模拟行为。为了对寄存器建模,设计器使用变量跨时钟事件存储数据。Verilog规范明确指出,变量并不意味着硬件寄存器[57],而是由合成工具来确定如何使用具体的硬件寄存器将always块的模拟行为映射到实现中。这种设计选择通过允许用户忽略程序如何在硬件中具体实现的细节来提高抽象级别。但是,它也消除了用户显式指定综合设计中使用的寄存器的能力。在实践中,这种选择可能导致寄存器合成的结果与设计者的意图不匹配。为了解决这个问题,Verilog设计团队强制执行样式指南,限制always块的使用,从而使合成结果透明。另一种设计可以使用限定符显式声明应该是硬件寄存器的变量。

选择如何将变量的概念映射到寄存器是所有必需RTL HDL的基本设计问题。一个相关的问题是协调寄存器的同步更新语义和标准变量的异步更新语义。例如,给定标准的命令式求值语义,对过程中两个不同变量的写入将发生在求值的不同步骤。但是,如果这两个变量都映射到硬件寄存器,则它们将在合成硬件中同时更新。一种设计选择是在语言的评估语义中显式地建模寄存器变量的同步时间更新语义,确保用户的计算模型与合成硬件的行为完全匹配。

Verilog的非阻塞分配提供了显式建模同步存储的能力。在Verilog中,在一个顺序代码块中的后续语句之前执行一个块赋值。相反,非阻塞分配不阻塞程序流,并且在时间步的末尾附近执行。当与时钟事件相结合时,非阻塞分配可用于通过延迟变量更新直到时钟周期结束来建模硬件寄存器的同步更新语义。

这两种赋值形式之间的相互作用构成了Verilog规范复杂性的一个主要组成部分。有人可能认为,非阻塞分配的语义可以简单地延迟评估,直到所有阻塞分配都完成。然而,对非阻塞赋值的求值将触发被赋值变量上的事件,这反过来又可能触发涉及阻塞赋值的事件。为了处理这个问题,Verilog的语义为每个时间步都包含一个循环,在阻塞和非阻塞分配之间移动,直到没有事件要处理为止。这些评估语义的复杂性使得很难对涉及这两种赋值形式的Verilog设计进行推理。在实践中,Verilog设计团队将遵循样式指南,以合理的理解方式强制使用赋值。

第2.3节中描述的功能性HDL演示了另外两种抽象寄存器概念的技术。一种方法是对函数接口中的状态进行编码。这是通过将电路描述为一个函数来实现的,该函数将当前状态作为其输入之一,并产生下一个状态作为其输出之一。这种形式的函数描述了有限状态传感器(FST)的转换函数,为当前状态存储在寄存器中的简单硬件合成算法提供了基础。这种技术必然意味着同步状态更新,因为状态的下一个值是在函数求值结束时生成的。无法在任何其他时间指定状态更新。

第二种方法使用基于流的抽象来编码状态。函数的输入和输出是一个流数据结构,带有一个特殊的延迟操作符,允许用户查看流的过去值。给定该运算符,用户可以描述其中输出流的值取决于先前时钟周期的输入流的值的电路。这种方法最简单的编译算法将插入寄存器来实现延迟运算符指定的行为。这种方法为处理输入的过去值提供了一种方便的抽象,但是它阻止用户显式地管理状态。例如,电路的输出可能依赖于对输入窗口值的计算。在这种情况下,将输入值上的部分计算存储为状态可能是最有效的,但是基于流的抽象迫使用户将计算描述为延迟输入流值的函数。编译器然后负责发现中间计算可以被存储的事实,而不是仅仅存储流值和重做计算。

硬件术语重写系统[32]通过将术语映射到同步存储元件并将规则重写到组合逻辑来抽象寄存器。这种方法与在函数接口中编码状态的函数hdl有许多相似之处。然而,TRS面临着一个独特的挑战,因为该技术在状态更新过程中引入了冲突的可能性。两个规则可能触发并尝试更新同一寄存器,这意味着编译器必须足够复杂,以检测冲突,并在可能时插入仲裁逻辑。在考虑规则的模块化组合时,这一问题变得更加复杂。编译器可以分别为每个模块调度规则,也可以将规则提升到单个顶层模块中,然后将其作为单个单元进行调度。先前的研究表明,这两种方法都是可行的,这取决于输入设计[36]。最小化编译器生成的用于调度重写规则的逻辑的开销是将术语重写系统用作寄存器传输抽象的关键挑战。

为有限状态机设计抽象是RTL语言的另一个重要设计问题。例如,Verilog提供了抽象,使逻辑综合能够生成fsm的优化实现。有限状态机综合的一个关键问题是状态的最佳表示。考虑一种设计,其中FSM的状态被执行算术运算的电路消耗。在这种情况下,使用非二进制编码将需要插入解码逻辑。另一方面,如果目标平台是FPGA,则单热状态编码通常更有效地映射到查找表结构。如图2所示,Verilog设计器可以使用参数来抽象状态的编码。控制逻辑对抽象的参数进行调度,具体的参数值可以通过自动化工具方便地更改或选择。

与状态编码的抽象相关的是有限状态机控制逻辑的综合。用于描述Verilog FSM的规范模式(如图2所示)使用了一个case语句来调度状态变量。Verilog case语句的语义为合成工具引入了复杂性,因为案例不一定是互斥的。此外,该工具还必须综合逻辑来处理尚未列出的案例的行为。例如,考虑具有12个状态的二进制编码的FSM。状态将以4位数量存储,用于分派case语句。在没有指导的情况下,合成工具必须足够复杂,以证明只有12个4位量的可能值,否则它必须插入额外的逻辑来处理非法值。SystemVerilog语言通过引入唯一的限定符来避免这个问题,该限定符表示所有的法律案例都已列出并且相互排斥。

Verilog有限状态机规范化设计模式中的一个主要问题是,对于具有复杂转换的大型有限状态机,描述严重缺乏结构。例如,Verilog中的一个简单SDRAM控制器包含25个状态,整个FSM转换行为在一个case语句中定义[21]。理解代码需要读者在任意情况之间进行大的跳跃。这种设计模式给设计者带来了巨大的认知负荷,他们必须管理大量复杂的时间行为来读取代码。大用例语句的使用与GOTO语句的使用有直接关系,我们认为这种设计模式同样有害(19)。

值得注意的是,这个程序结构问题并不局限于硬件有限状态机的描述,实际上是命令式语言的一个更一般问题的实例。幸运的是,软件社区已经找到了一个基于协程的有前途的解决方案[10]。最近的工作是通过限制协程的语义来研究这种技术在硬件有限状态机中的应用,以便能够精确地编译成电路[60]。主要的挑战是限制协程语义只能描述有限状态机,同时仍然支持使用协程组合。

这种技术的本质是增强verilog always块的语义来描述协同程序。设计者可以在任意位置挂起该过程,以便在代码中包含更多的结构。例如,可以通过用yield语句分离逻辑来实现两个状态的排序,并且可以使用包含yield的while循环来描述状态的循环。将此与case语句模式进行比较,在case语句模式中,序列和循环的结构在case的平面列表中不显式。

一个相关的问题是对有限状态机顺序组成的描述。仅使用由基本RTL抽象组成的电路抽象,通过在两个电路之间使用导线来实现不同FSM电路的顺序组合。这些导线用于中继信号,指示FSM应启动或FSM已结束。为了抽象出这些连线和相应的控制逻辑,Lava的创造者开发了Pace[13]语言。布拉尼,一种现代变种熔岩,以配方的形式提供了类似的概念[44]。Bluespec的开发人员还创建了类似的语言STMTFSM[48]。所有这些语言的基础是程序片段的模块化、顺序组合的概念。关于Silica语言的早期工作[60]正在探索使用协同程序组合作为模块化、顺序组合的另一种抽象。

3.1.3 虚拟机抽象

虚拟机抽象将硬件建模为抽象机的一组指令。这种技术隐藏了在较低抽象级别中发现的某些细节,例如资源的有限性。例如,C语言提供了一个虚拟机的抽象,这个虚拟机可以存储无限多的变量。为了综合一个C程序的硬件实现,编译器必须执行一种寄存器分配的变体,根据用户提供的一组约束将变量映射到寄存器。从历史上看,这种方法主要应用于从传统软件语言(如C)合成硬件,但是一种新兴的工作正在探索这种技术在软件dsl中的应用。

这种方法的主要优点是,它使用户能够像开发软件一样设计硬件,从而极大地提高了生产率。然而,在实践中,为了达到预期的性能,用户需要对他们试图生成的硬件有深入的了解[46]。这在很大程度上否定了使用传统软件语言的优势,因为用户必须打破虚拟机的抽象,并对如何将程序映射到硬件进行推理,而不是简单地对软件程序进行推理。设计基于虚拟机抽象的语言的中心挑战是找出硬件的哪些方面可以抽象,以便在不削弱编译器性能的情况下提高生产率。

将通用软件程序编译成硬件的问题与自动并行通用软件程序的问题有许多共同点。幸运的是,最近的工作反映了并行计算的领域,利用dsl来促进更好的编译器到硬件的映射。dsl能够通过利用特定领域的抽象来提供生产力和性能。

例如,最近对Halide(一种用于高性能数组和图像处理代码的DSL)的研究,通过引入针对特定硬件优化的指令,扩展了编译器以支持硬件合成[53]。这种方法保持了用于描述图像处理算法的虚拟机抽象,同时使用户可以在一定程度上控制编译器如何合成硬件。虽然这种技术仍然要求用户考虑他们正在设计的硬件,但它避免了为了影响编译器输出的更改而更改原始源输入。这种方法的主要优点是,用户可以通过指导编译器而不是依赖于基于启发式的优化来获得所需的综合结果。

Spatial[38]DSL采用另一种方法来简化问题,通过引入虚拟机抽象和内存的替代设计。空间程序没有使用标准cpu提供的统一可访问的地址空间抽象,而是显式地与内存层次结构交互。这种设计选择的动机是这样一个事实:将通用软件程序编译成硬件的一个主要挑战是确定最佳的内存体系结构。Spatial允许用户使用模板显式地设置内存体系结构,同时仍然利用编译器来调度计算的其他方面。Spatial就是这样一个例子,它抛弃了大多数现代软件语言所使用的传统虚拟机抽象,取而代之的是针对硬件编译问题而定制的新抽象。

Halide方法和空间方法的基础是一种技术,它涉及到为编译器识别一个关键问题,并开发一种语言抽象来简化这个问题。展望未来,对开发基于虚拟机抽象的HDL感兴趣的研究人员应该探索平衡用户生产力和编译器合成的硬件质量的技术。

3.2 编译器基础结构

基于LLVM的软件语言的激增[40]证明了共享编译器基础设施对于工业和学术目的的价值。对于研究人员来说,LLVM提供了一种快速原型化语言的方法,而无需实现标准编译器过程或为标准体系结构创建后端。为硬件编译器开发公共基础设施的工作正在进行中,并且已经阐明了与软件编译器相对应的关键问题[34,15]。显然需要开发特定于硬件的编译器过程。优化过程是至关重要的,因为HDL中的新思想如果不能被编译成高性能的实现,将看不到任何实际用途。

虽然一些标准的编译器过程(如常量折叠)可以直接应用于HDL,但存在一整类特定于硬件的过程。例如,硬件计算总是在这样一种意义上被断言:如果一个计算被映射到物理组件,那么这些组件将持续执行。在数据流上使用多路复用器实现条件逻辑。为了简化条件逻辑的降阶,可以将程序重写为单一的静态赋值形式。在软件中,将其保留为这种形式会产生成本,因为非遍历分支中的指令总是会被执行。但是,硬件已经是这样了,所以将程序描述留在这个表单中不会产生任何成本。实际上,这简化了编译器的合成阶段,实现了从phi节点到多路复用器的一对一映射。对开发HDL编译器基础设施感兴趣的研究人员面临的主要挑战将是设计可重用的、特定于硬件的分析和转换过程。

另一个阻碍设计生产力的因素是开发针对新体系结构的软件编译器。例如,开发对RISC-visa[3,64]的扩展需要扩展一个现有的编译器后端来针对新的指令。这意味着硬件设计团队必须包括编译器专家,这反过来表明需要能够自动合成新硬件体系结构的编译器后端。Tensilica处理器生成器[25]演示了自动生成针对新指令的编译器的可行性。然而,这种能力要求用户遵守固定的处理器体系结构。未来的工作应该探索扩展这种技术,以支持更广泛的体系结构类的扩展。

考虑到许多软件编译器已经为后端目标聚合到ISA抽象上,HDL社区聚合到机器可读的ISA规范语言上是至关重要的。收敛性将允许研究人员为使用标准输入格式描述的新ISA进行自动合成编译器后端的实验。ISP[7]是可以描述isa的处理器规范语言的一个较老的例子。Peak语言的早期研究[28]正在探索使用smt-lib[9]来开发具有形式语义的ISP的现代变体。

最后,硬件编译器开发人员面临的一个关键问题是编译器本身的性能。例如,最近一篇文章[37]鼓吹一种高生产率硬件设计的新方法,报告说将他们的RTL设计编译成集成电路布局只需要12个小时。这是设计空间探索过程中的一个明显瓶颈。他们减少编译器运行时间的技术是基于降低位置和路径的复杂性,这是编译器中的一个阶段,设计的逻辑组件被放置到物理空间中。优化硬件编译器的位置和路由阶段对于有兴趣改进HDL编译器运行时性能的研究人员来说只是一个机会。

3.3 形式化方法

编程语言长期以来享有丰富的优雅理论,这些理论构成了有用的形式化方法的基础。按照Grothendieck[42]的风格,从事基础理论研究的研究人员创造了一个技术海洋,用于开发解决难题的实用方法。WebAssembly[26]最近的发展和扩散证明了在设计一种新语言时考虑形式化规范的实用性。在这个新的HDL黄金时代,研究人员应该利用这个机会开发专门为高级形式化方法的应用而设计的新语言,而不是面对将形式化方法改造为旧语言设计的挑战。

3.3.1 执行语义

形式化HDL的执行语义是与模型检查器等形式化工具集成的基本要求[14]。主要的挑战是捕获硬件中固有的并发性和并行性。过程计算[5],特别是时间概念[6]提出了一种方法。实时时间和离散时间可以分别用来描述模拟电路和数字电路的语义。一个问题是混合信号电路建模的实时和离散时间的集成。一个类似的问题是同步和异步数字逻辑的建模。通信顺序过程[31]是一种应用于异步电路建模的技术[62]。

电路抽象作为一种表达完整的原语的存在,让人想起软件语言领域的功能抽象。这就提出了一个问题,即是否可以构造一个核心演算来捕获电路抽象的执行语义,就像lambda演算[8]捕获函数抽象的语义一样。虽然函数抽象为这种微积分的发展提供了一个令人信服的基础,但有两个关键问题必须解决:电路可以保持状态,并且必须具有有限的大小。这与通过递归描述无限计算的函数抽象的基本定义形成对比。类型系统可以用来强制执行计算的有限性[49],这就留下了管理状态的问题。第2.3节讨论了在功能性HDL中编码状态的两种技术。使用这些技术的关键挑战之一是它限制了语言描述同步电路。对社区的一个重要贡献将是开发一种可以捕获同步和异步逻辑的状态编码机制。

3.3.2 类型系统

Verilog是主导HDL的事实表明,硬件社区没有享受到类型系统最新进展的好处。ARM Advanced Peripheral Bus(APB)接口[41]在端口名中使用特殊前缀来表示它们是协议的一部分,这一事实证明了这一点。这要求用户使用名称匹配来管理接口连接,这比在类型系统中嵌入名称匹配所能提供的安全性要低得多。

一个主要问题是Verilog类型系统没有提供代数数据类型的概念。引入有限大小产品类型的概念将使APB接口规范能够被定义为元组或记录类型,而不是使用命名约定。产品类型的使用为HDL设计者提供了与软件开发者相同的好处。它们也是无开销抽象的一个例子[61],因为它们可以通过将类型展平到叶元素中来从设计中编译出来。将此与sum类型进行比较,sum类型需要在生成的设计中插入额外的逻辑来区分变体。尽管成本如此,sum类型仍然提供了与软件相同的有用静态保证。它们还提供了一种机制来抽象出控制逻辑的细节,这为编译器综合优化的实现创造了机会。

另一个有趣的研究途径是将行为类型[2],特别是会话类型[33]应用于硬件接口。硬件通信协议表现出许多与会话类型已经应用到的软件协议相同的特性。核心问题是将会话类型语义编织成HDL执行语义。对这个问题感兴趣的研究人员应该考虑硬件协议的域如何与更一般的软件协议不同,目的是寻找使问题更简单的机会。硬件协议的一个关键方面是使用魔术位模式对协议的部分进行编码。更一般地说,硬件协议可以涉及依赖于数据的通信。这为应用依赖类型技术指定通过接口移动的数据值的属性提供了机会。虽然这通常是一个困难的问题,但将域限制为硬件协议可能会为这些思想的实际应用提供机会。

4 Vision:一个用于硬件构建的多语言系统

HDL的黄金时代提供了一个试验替代HDL设计的机会。本节介绍了一个多语言系统的远景,其中使用元编程的主机语言来实现用于硬件构建的嵌入式dsl。多语言方法直接受到Lua/Terra[17,16,18]的启发,Lua/Terra是一种两种语言系统,它将静态类型的低级编程语言与动态类型的高级语言集成在一起。与软件开发非常相似,硬件设计涉及用多种语言编写的组件。例如,一个特定组件的软件模型可以用C实现,并由Verilog编写的测试使用。此外,可以使用Perl元程序生成的Verilog来定义模块的硬件实现。

与Verilog一样将HDL作为一种独立的语言来对待不同,这个设想采用了在通用编程语言中嵌入HDL的方法。这一设想基于一个核心结构的嵌入式DSL,该DSL被用作大量DSL的公共编译目标,每个DSL都针对硬件设计过程的各个方面。将硬件设计过程的各个方面统一为同一语言的子集,可以减少硬件设计者的认知负荷。他们只需要学习一个语法,通过嵌入的集成使dsl能够在不需要粘合代码的情况下合成。

4.1 元程序主机语言

这种多语言系统的愿景是基于元编程的宿主语言。它可以被元编程的程度必须支持富dsl的实现。例如,Magma[27]使用Python的元类特性来嵌入电路抽象,并且Silica[60]检查Python AST以编译到硬件有限状态机的协程。这些dsl的实现需要对元编程的语言支持,这比简单的预处理要丰富得多。这个需求的一个副作用是,宿主语言的元编程特性将成为嵌入式dsl的元编程特性。

标准的多阶段编程方法足以支持实现硬件生成器所需的灵活代码生成[51]。硬件生成器是使用一组参数并生成硬件设计实例的程序[54]。在元编程主机语言中嵌入HDL可以使用标准元编程技术实现硬件生成器。将多级编程技术应用于硬件生成器比在软件领域要容易一些,因为在实践中,元语言和HDL之间的交互是单向的。将此与Lua/Terra进行比较,Lua/Terra可以在两种语言之间传递控制。在硬件生成器中,元程序构造HDL程序的片段,但生成的HDL代码通常不会调用宿主语言中的代码。在理论上,这可能是一个可重构的硬件系统,但在实践中,这是由硬件编译器的缓慢性能限制。提高编译器性能可以为硬件构建JIT编译器系统,然后可以利用生成器代码和生成的硬件之间的双向交互。

一个关键问题是宿主语言是静态类型的还是动态类型的。主要的权衡是在生产力和正确性之间。静态类型的宿主语言将提供更高的安全性,这对于大型复杂系统是可行的。然而,动态类型语言将促进快速设计空间探索,并为更复杂的硬件生成器提供所需的灵活性。例如,动态类型语言中的生成器可以使用动态构造的类型。另一个重要问题是类型系统对用户的认知负荷。硬件设计师不是软件工程方面的专家,因此可以从简单易懂的类型系统中获益匪浅。此外,生成的硬件设计的正确性比用于构建设计片段的生成器的正确性更重要。这些需求表明,基于动态类型的宿主语言(如Python)的系统由静态类型的嵌入式DSL组成,这是一个平衡生产力和正确性的令人信服的解决方案。像Python这样无所不在的语言还有一个额外的好处,许多硬件工程师可能已经在编写脚本时遇到过它。将其与Scala语言相比较;虽然它为构建dsl提供了许多引人注目的语言特性,但硬件工程师在学校或专业工作中遇到这种语言的可能性很小。

4.2 核心结构DSL

在宿主语言之后,视觉的第二个基本要素是提供结构化电路抽象的嵌入式DSL。这个核心DSL的定义应该简单而精确,因为传统HDL的许多复杂性将被转移到其他DSL或宿主语言上。如第3.1.1节所述,电路抽象是表达完整的,这意味着这种结构化DSL可以作为系统中所有其他语言的通用编译器目标。这种设计允许使用结构抽象来组合在不同dsl中定义的模块。这是通过执行分阶段执行来实现的,在最后阶段,所有程序片段都已编译到核心DSL。在执行的最后阶段,用户定义了一个程序,从结构上组成各个组件。Magma[27]和clive[4]是嵌入式结构语言的具体例子,可以达到这个目的。一个重要的要求是正式指定这个核心语言,然后为系统中其他dsl的正式规范提供一致的基础。

4.3 硬件DSL的海洋

主机语言与嵌入式核心结构HDL的结合是研究和开发其他DSL的基础,以解决第3节中讨论的智力挑战。例如,最近的工作使用了Magma[27]和Python作为开发指定处理元素的峰值语言[28]的基础。Peak支持编译到Magma,然后可以将Magma与其他DSL中编写的其他组件组成,比如Silica[60],一种使用协程描述硬件有限状态机的DSL。本设计的一个主要主题是通过分离关注点来分离关注点语言. 也就是说,不同硬件组件的描述可以受益于使用不同的抽象集来描述。如果是这种情况,这些组件可以使用不同的dsl实现,并通过定义良好的结构接口进行组合。上述dsl解决具体硬件设计的特定问题。这一愿景包括另一类面向特定应用程序的dsl。例如,基于Numpy[63]的DSL可用于将数值计算算法编译成硬件电路。虽然这些语言应该主要设计为向用户提供特定于应用程序的抽象,但它们也应该设计为与核心结构DSL进行互操作。这将使用面向应用程序的dsl编写的代码能够与为应用程序加速器生成工具的库集成。在这种情况下,库例程可以引用算法的编译版本,并使用核心结构DSL将其连接到其他组件。

4.4 验证

因为宿主语言是一种通用编程语言,所以它为执行验证任务提供了必要的工具。其基础是主机语言中的通用代码与核心结构DSL中定义的电路之间的连接。最近关于故障的研究[59]通过开发一种嵌入式DSL探索了解决方案,这种DSL允许用户通过一组动作与电路进行交互。这种方法的一个主要优点是,它可以将验证组件(如随机数生成)实现为宿主语言中的库。此外,测试可以以与硬件相同的方式进行元编程,这通过更灵活的测试基础设施降低了验证成本。将这种方法与SystemVerilog进行比较,SystemVerilog中描述硬件的核心语言扩展为专门用于验证的抽象,例如类系统和字符串数据类型。随着时间的推移,这导致了SystemVerilog规范中的特性蠕变和复杂性。这是vision的基本设计模式的另一个例子,它基于与HDL无关的硬件特定的解耦特性。

5 结论

PL社区站在通往计算机体系结构新黄金时代的关键道路上。幸运的是,有大量的智力挑战表明,我们正处在一个新的黄金时代的风口浪尖。本文提出了一个多语言系统的硬件建设,将提供所需的生产力增益来推动这个新的黄金时代的计算机体系结构的愿景。对于一个对PL和硬件感兴趣的研究人员来说,这是一个激动人心的时刻。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值