嘿!您似乎在 United States,您想使用我们的 English 网站吗?
Switch to English site
Skip to main content

学习Verilog语言基础,在Chip Hack EDSAC Challenge上驱动纸带穿孔机

chiphackwelcome_023db6f38511bee950f4dbd927e5aa25f739972c.jpg

Chip Hack EDSAC Challenge成为2017年  Wuthering Bytes节日 的一部分。该活动由BCS Open Source Specialist Group (BCS OSSG)和 Computer Conservation Society (CCS)主办,由Embecosm提供,旨在向世界推广FPGAs 和硬件描述语言(HDL),本案例中介绍Verilog。

类似的活动以前也举办过,在今年合并推出了一些关键的事物,虽然这些事物不是最有趣的,但是包含了过去的见解。其中有趣的一点是,整个活动都是围绕FPGA工具链。

EDSAC

上一篇文章中,我们讨论了EDSAC的背景。在早期的计算机时代,EDSAC是早期非常卓越的计算机。CCS和 The National Museum of Computing正在制作一个全尺寸的EDSAC复制品,其所用硬件和原来的机器一样。这已经接近完成状态,并且在短时间内,您不仅可以访问它,还可以在它上面运行代码。

Chiphacktape1_006ef75208adfaaa237fa2a8ab83c1756a73b76a.jpg

硬件描述语言

HDL不这是一个术语,它影响着我们的日常生活。你的智能手机,电脑,手表,甚至是牙刷(如果你有电动牙刷的话),它们里面的设备都是用HDL设计的。世界上几乎所有的IC都含有某种形式的HDL。

HDL主要有两种VHDL和Verilog。这并不是说没有其他语言,但就像软件一样,有些语言相比而言更普遍。在某些方面,有些语言比其他语言功能更强大。虽然Verilog更倾向于芯片设计,VHDL更适用于FPGA,但这并不是相互排斥的,这两种语言都可用于这两个领域,就像Java和c++一样。

在Chip Hack活动中选择了Verilog语言,它比VHDL更像c语言,所以对于那些以前没有使用过HDL的人来说这是更好的选择。

的设计超出了范围

虽然HDL可以快速编码,但将其转换为物理硬件的过程相当复杂。因此,世界上只有屈指可数的几个硅铸造厂或 “fabs” 。生产晶片与最终形成芯片的过程是非常昂贵的——即使是运用旧的技术。大多数晶圆厂都是建立在很高的产量上,每天/周生产数以百万计的晶片与芯片。那么我们如何测试我们写的Verilog呢?

介绍现场可编程门阵列(FPGA)。自80年代中期以来,FPGA这个相对较老的技术,在某些应用之外的吸引力有限。一些原因造成了其局限性,但其中很主要的一个因素是成本。直到最近,它们都很昂贵——与ASIC不成比例,以至于不能成为商业电子产品。

它在改变,而且更倾向于节约成本,并且有一些设备选择FPGA在他们的设计中起主要的作用。HTC Vive VR耳机就是一个例子,使用 FPGAs来完成传统ASICs不能完成的设计。第二个例子是移动市场使用FPGA实现DSP功能,虽然一些软件可以做同样的工作,但它们完成同样的任务时,需要的功率比FPGA更大,示例包括语音识别。FPGA行业的大多数主要生产商已经开始生产“小型”的FPGA来填补这些功能所需。事实证明,所谓的“小”一点也不小,EDSAC能够很容易适配这些设备中最小的部分。

MyStorm — iCE40

mystorm1_1ae25a79af37fb6bbebb528d686511ccf0da07c4.jpg

myStorm是Alan Wood和Ken Boak最近创建的,一个基于FPGA设计的 Lattice iCE40。这个设计的催化剂是 Clifford Wolf的IceStorm项目,它提供了第一个完全开放的FPGA流程。myStorm项目诞生于市场上出现的FPGA流程与节约成本型FPGA之间。

开始

运行一种新语言可能会让人望而生畏,然而大多数软件语言都遵循同样的主题;软件通常以线性方式运行,并发代码不是标准。即使我们使用线程来并发代码,这样做也是相当明确的。当我们最终运行并发代码线程时,在CPU中,这些线程是逐个运行的,而不是并行运行的。当我们进入多核系统时,这种情况正在改变,大多数软件真正的并行计算是抽象的,我们不必担心。

Uart_5ecc3d718d4b65aea67b8fde72050c3452d558ee.jpg 这不是HDL的案例,Verilog看起来像C语言,然而我们所描述的是数字电路,它们不是一个一个运行的,它们是并行运行的。实际上,让系统按顺序运行时,需要特别注意,因为这不是硬件的标准。

在某种程度上,第一天的大部分时间都花在了最简单的设计上,以便有效地使用硬件。

我们都必须从某个地方着手,因此例1让一个LED灯发光是一个好的开始。人类可读的名称供给芯片配置,留下了单个Verilog文件:

module led (output led);
	assign led =1;
endmodule

这很简单

从“led =”按钮迅速升级到闪烁的led灯。

module blink(input clk, output led);
	reg [24:0] count;
	assign led = count[24];

	always @(posedge clk)
	    count <= count + 1;

endmodule

在这点上,我们已经从组合逻辑转换到顺序逻辑,从阻塞到非阻塞的分配。这是我们需要详细了解的一个关键的区别。

组合逻辑

当我们想象一个逻辑电路时,我们通常会想到组合逻辑。下面的电路就是一个很好的示例。与门将立即反映出异或与非门输入的变化,即并行任务。

comb1_9324e6ec8cd8af71ad79be7bb9a1d09a2fc9d22f.jpg

 

顺序逻辑

为了使电路在顺序逻辑之上,我们需要对信号进行控制。通过在输出上使用D型触发器,我们可以极大地改变电路的性能。在这个示例中,我们将锁定输出并将其与内部时钟同步。

如上图所示,如果我们使用顺序逻辑,我们可能会错过输出“X”。然而,通过使用顺序逻辑

,我们保留了X的状态,直到我们准备就绪(状态“Y”)。

seq_9324e6ec8cd8af71ad79be7bb9a1d09a2fc9d22f.jpg

logic1_d103d74c59858f03140db6da6890417c1c17eed5.jpg

 

阻塞VS非阻塞

虽然解释起来有点困难,但是我们会使用代码呈现。输出n,输入我们希望存储的n - 1(n1)然后时钟输出y。

always @(posedge clk)
begin
	n1 = n;
	y = n1;
end

随着n的变化n1也在改变。因此,实际上在任何情况下n = n1。当n1最终取n时(这可能是一个复杂的组合逻辑块),我们也无法控制其结果。最终结果是y = n。

让我们将其更改为非阻塞:

 

always @(posedge clk)
begin
	n1 <= n;
	y <= n1;
end

在时钟的上升沿,n将被赋值为n1。y也会取n1的状态,但这一次是在时钟的边沿上,所以y = n- 1而不是n !

原创作品

随着活动的进展,我们很快掌握了获取EDSAC示例所需的(主要)技能。尽管取得了惊人的成就,但使用提供的代码与创建原创作品是不一样的。因此,在这一点上,我们被放开,以创造我们希望的任何东西。不想浪费花在 PSoC powered tape punch上的努力,我们决定为该活动创建一个清晰的标题来纪念。如果你读过上一篇文章,你可能已经注意到在里面拍摄的标题。

在最初尝试创建一个三重嵌套的状态机设计时,我们遇到了瓶颈,我们(非常感谢Embecosm的想法)认为创建数据流并直接从单个寄存器中轮转数据可能更简单。

我们使用含有时钟,由5位数据配置的punch,使用电子表格来创建清晰的模式变得非常简单。

HbAAAAAElFTkSuQmCC_91fead7f87059e5854e9627fcf43da8c2b9d0f40.png

 

 

 

 

 

  

从这里开始,构建一个465位长(93字符长)的数据流,并以465b为前缀,告诉Verilog如何存储数据:

465'b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111110101100010000011111100010111000000110011010110011000001111110100111110000011111100011000100000000000000011111100011000100000111110010011111000001000111111100010000011111101001110000000000000000011111001001111100000111111010011111000001111110001100010000011111001101101100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;

如果我们有下面的代码,我们就可以加载“out”,数据从移位寄存器移出分配给正确的引脚。

out <= data[464:460];  // output the top 5 bits of data
data <= data << 5; // shift the data for next time

下一步,我们需要一个状态机来控制操作状态:

  • 无所事事/不做事/重新装车
  • 穿孔维护数据
  • 离开维护数据并穿孔

这相当于一个4状态的状态机:

// The state machine
// 0 - initial state
//     action: get the next 5-bits
//     goto state 1
// 1 - assert punch
//     goto state 2
// 2 - deassert punch and initiate punching until done
//     if not done goto state 0
//     if done goto state 3
// 3 - idle state
//     goto state 3
reg [1:0] state = 3;

经过大量的编码和少量的实验,我们最终得到了下面的代码,它曾经加载到FPGA上,让我们的核心内容有了清晰的标题:

module punch(input clk, input reset ,input but0, output led,output led2,output led3, output led4, output D8, output D7, output D6, output D5, output D4, output pclk);
 

	reg slowclk;
	reg [4:0] out; // register to hold output
	// reg punch; // punch control not used
	reg [7:0] charcount;  // Number of 5-bit char blocks. Enough for up to 256 chars (this would include lead in and out)

	// The state machine
	// 0 - initial state
	//     action: get the next 5-bits
	//     goto state 1
	// 1 - assert punch
	//     goto state 2
	// 2 – de assert punch
	//     goto state 0
	// 3 - idle state
	//     goto state 3
	reg [1:0] state = 3;
	
	// The data to punch
	reg [464:0] data;
	
	assign {D8,D7,D6,D5,D4} = {out}; // map the output pins to the data

  	reg [21:0] count; // register to hold clock counter
	assign slowclk = count[21]; // create a much slower 100Mhz/65536 around 1.5khz
    
	// increment the counter when we get a clock
	always @(posedge clk)
		count <= count + 1;
	
	// State machine code
	always @(posedge slowclk) begin
	   if (reset == 1'b0) begin
	      
		  pclk <= 1'b0;  // pclock is the Punch out clock
		  state <= 3;  // Idle state
		  led4 <= 1'b0; // status leds
		  end
	   else begin
	      case (state)
		     0: begin
			    // Initial state
				out <= data[464:460]; // out takes the top 5 bits of data
				data <= data << 5; // shift data for next time
				state <= 1; // on the next clock start state 1
				led <=1'b0; // status leds
				led2 <=1'b1; // status leds
				led3 <=1'b1; // status leds
				led4 <=1'b1; // status leds
				end
				
		     1: begin
			    // Assert punch
				pclk <= 1'b1; // punch (neg edge triggered) clock high
				charcount <= charcount - 1;  // Do here, so ready by next state;
				state <= 2; // on the next clock start state 2
				led2 <= 1'b0; // status leds
				end
				
			 2: begin
			    // Deassert punch, which will trigger the action (negedge)
                		pclk <= 1'b0; // punch (neg edge triggered) clock low so clock in and punch
				led3 <=1'b0; // status leds
				state <= (charcount == 4'b0) ? 3 : 0;  // if statement equivalent of if(charcount = 0000) then state=3 else state =0 e.g. wait for all chars to be punched before idling
				end
				
			 3: begin
			    // If we get here, wait for buttun0 or reset.
				led <=1'b1; // status leds
				
				// this is the data to punch
				data <= 465'b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111110101100010000011111100010111000000110011010110011000001111110100111110000011111100011000100000000000000011111100011000100000111110010011111000001000111111100010000011111101001110000000000000000011111001001111100000111111010011111000001111110001100010000011111001101101100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
				charcount <= 93;  // load the char count
				state <= (but0 == 1'b0) ? 0 : 3;// if statement equivalent of if(but = 0) then state=0 else state =3... e.g. wait for button before punching
				end
		  endcase
		end
		end
endmodule

 

总结

我们在Chip Hack EDSAC Challenge中玩得很开心。如果您想要自己尝试EDSAC和编码,甚至运行自己的Chip Hack,那么所有的notes和workshop材料都可以在chiphack.org上找到。

Verilog是一款非常强大的工具,虽然很难掌握,但我们期待在将来能够更频繁地使用到它。

Karl Woodward

 

 

 

Karl is a design engineer with over a decade of experience in high speed digital design and technical project leadership in the commercial electronics sector.
DesignSpark Electrical Logolinkedin