行情
HOME
行情
正文内容
verilog nand与nor Vivado使用技巧-支持的Verilog语法
发布时间 : 2024-11-24
作者 : 小编
访问数量 : 23
扫码分享至微信

Vivado使用技巧-支持的Verilog语法

复杂的电路设计通常使用自顶向下的设计方法,设计过程中的不同阶段需要不同的设计规格。比如架构设计阶段,需要模块框图或算法状态机(ASM)图表这方面的设计说明。一个框图或算法的实现与寄存器(reg)和连线(wire)息息相关。Verilog便具有将ASM图表和电路框图用计算机语言表达的能力,本文将讲述Vivado综合支持的Verilog硬件描述语言;

Verilog提供了行为化和结构化两方面的语言结构,描述设计对象时可以选择高层次或低层次的抽象等级。使用Verilog设计硬件时,可以将其视作并行处理和面向对象编程。Vivado综合支持IEEE 1364标准。Vivado综合对Verilog的支持可以用最有效的方式描述整体电路和各个模块。综合会为每个模块选择最佳的综合流程,将高层次的行为级或低层次的结构级转换为门级网表;

1.Variable Part Selects 可变部分选择

除了用两个明确的值限定选择边界外(如assign out = data[8:2]),还可以使用变量从向量中选择一组bit。设置一个起始点和截取的宽度,起始点可以动态变化,示例如下:

reg [3:0] data;

reg [3:0] select;

wire [7:0] byte = data[select +: 8]; //+、-表示从起始点开始增加或减少

2.Structural Verilog 结构化verilog

Verilog可以进行多个代码块设计,并按一定的设计层次组合起来,下面给出于此相关的重要概念:

组件(Component):结构化设计中的一个基本块;

申明(Declaration):组件与外部交流的信息;

主体(Body):组件内部的行为或结构;

端口(Port):组件的I/O;

信号(Signal):组件与组件之间的连线;

一个组件用常见的模块(module)来表示,组件之间的连接由实例化(instantiation)声明实现,实例化声明规定一个组件在另外一个组件或电路中的实例,赋予标识符,并用关系列表设定信号与端口之间的联系;

除了自己设计的组件外,结构化Verilog还支持实例化预定义的原语:逻辑门、寄存器、Xilinx特定的原语(如CLKDLL、BUFG),这些原语都定义在Xilinx Verilog库文件unisim_comp.v中,逻辑门原语包括AND、OR、XOR、NAND、NOR、NOT,实例化这些逻辑门来搭建更大的逻辑电路,示例如下:

//实现2输入或非逻辑功能

module build_xor

(

input a, b,

output c

);

wire a_not, b_not;

//每个实例必须有不同的实例化名称

not a_inv (a_not, a);

not b_inv (b_not, b);

and a1 (x, a_not, b);

and a2 (y, b_not, a);

or out (c, x, y);

endmodule

//实例化预定义的原语FDC和BUFG

module example (sysclk, in, reset, out);

input sysclk, in, reset;

output out;

reg out;

wire sysclk_out;

FDC register (out, sysclk_out, reset, in); //position based referencing

BUFG clk (.O(sysclk_out),.I(sysclk)); //name based referencing

3.Verilog Parameters verilog参数

参数化代码提高了可读性和代码紧凑型、容易维护和再使用。一个Verilog参数(parameter)就是一个常数(不支持字符串),且实例化参数化模块时可以改写参数值,下面给出示例:

//Verilog参数控制实例化块寄存器的宽度

module myreg #(parameter SIZE = 1)

(

input clk, clken,

input [SIZE-1:0]d,

output reg [SIZE-1:0]q

);

always @(posedge clk)

if (clken) q <= d;

endmodule

//顶层模块

module test #(parameter SIZE = 8)

(

input clk, clken,

input [SIZE-1:0] di,

output [SIZE-1:0] do

);

myreg #SIZE inst_reg (clk, clken, di, do);

endmodule

module parameter_generate_for_1 (clk, si, so);

parameter SIZE = 8;

input clk;

input si;

output so;

reg [0:SIZE-1] s;

assign so = s[SIZE-1];

always @ (posedge clk)

s[0] <= si;

genvar i;

generate

for (i = 1; i < SIZE; i = i+1)

begin : shreg

always @ (posedge clk)

begin

s[i] <= s[i-1];

end

end

endgenerate

endmodule

4.Verilog Usage Restrictions Verilog使用限制

在Vivado综合中用到的Verilog语法有如下3点限制:

大小写敏感:Verilog是一种大小写敏感的语言,但在Vivado中,只有实例和信号名称会区分大小写。如果两个module名称只有大小写不同,综合时会报错

阻塞和非阻塞赋值:不要混合使用阻塞和非阻塞赋值。尽管综合时可能不会报错,但在仿真时会出现错误

整数的处理 某些情况下,Vivado综合器处理整数时与其它综合工具方法不同,因此必须使用特定的代码编写方式。例如在Case语句或拼接语句中,使用未定义大小的整数都会导致无法预料的结果;

下面给出两个错误例子:

//同一信号不要混用阻塞和非阻塞赋值

always @(in1)

if (in2) out1 = in1;

else out1 <= in2;

//同一信号的不同bit不要混用

if (in2) begin

out1[0] = 1'b0;

out1[1] <= in1;

end

else begin

out1[0] = in2;

out1[1] <= 1'b1;

end

整数处理方式不当引起错误的情况:

reg [2:0] condition1; always @(condition1) begin

case(condition1)

4 : data_out = 2; // Generates faulty logic 未声明4的位宽,而condition1的位宽为3

3'd4 : data_out = 2; // Does work

endcase

end

//拼接语句

reg [31:0] temp;

assign temp = 4'b1111 % 2; //未确定位宽的运算用临时信号存储

assign dout = {12/3,temp,din}; //12/3运算位宽不确定,结果错误

5. Verilog System Tasks and Functions 系统任务和函数

Vivado综合支持的Verilog构造与系统任务包括:

整数、实数、assign(有限制)、deassign(有限制)、repeat语法(重复值必须是常数)、for语法(范围必须是静态的)、disable(不能用于for循环和repeat循环)、module定义、defparam、实例数组、`default_nettype、`define、`ifdef、`ifndef、`elsif、`include、`file、`line、$fclose、$fgets、$fopen、$fscanf、$readmemb、$readmemh、$signed、$unsigned、$floor(仅用于参数)、$ceil(仅用于参数)。

Vivado综合不支持和会忽视的的Verilog构造和系统任务包括:

字符串、网络类型(tri0、tri1、trireg)、驱动强度、实数和实时寄存器、命名事件、事件(@)、延迟(#)、force、release、forever语法、wait、并行块、设定块、macromodule定义、层次结构名称、`celldefine、`endcelldefine、`resetall、`timescale、`unconnected_drive、`nounconnected_drive、`uselib、$display、$fdisplay、$finish、$fwrite、$monitor、$random、$stop、$strobe、$time、$write、$clog2(仅SystemVerilog支持)、$rtoi、$itor、all others。

介绍其中几个非常常用的系统任务:

$signed和$unsigned可以强制规定输入数据为带符号数或无符号数,并作为返回值,不用管之前的符号。

$readmemb和$readmemh可以用于初始化块存储器,两者分别用2进制和16进制表示。如“$readmemb(“ram.data”, ram, 0, 7)”;

6.Verilog Primitives 原语

Vivado支持上文列出的Verilog门级原语,但不支持上拉下拉、驱动强度和延迟、原语矩阵这些类型的门级原语,也不支持如下转换级原语:cmos、nmos、pmos、rcmos、rnmos、rpmos、rtran、rtranif0、rtranif1、tran、tranif0、tranif1;

实例化门级原语的示例如下:

gate_type instance_name (output, inputs); //语法模板

and U1 (out, in1, in2);

bufif1 U2 (triout, data, trienable);

7.Behavioral Verilog 行为级verilog

行为级Verilog中的变量都申明为整数,数据类型可以是reg(程序块中赋值)、wire(连续赋值)和integer(会被转换为寄存器类型);所有变量的默认位宽为1bit,称作标量(scalar);定义的N bits位宽变量称作向量(Vector);reg和wire可以定义为带符号数signed或无符号数unsigned;变量的每个bit可以是如下值:1(逻辑1)、0(逻辑0)、x(未知逻辑值)、z(高阻);

reg [3:0] arb_priority;

wire [31:0] arb_request;

wire signed [8:0] arb_signed;

寄存器在定义时可以初始化,初始值是一个常数或参数,不能是函数或任务的调用;在全局复位或上电时,Vivado综合会将初始化值作为寄存器的输出(作为寄存器的INIT属性值);而且该初始值与本地复位是相互独立的 ;

reg arb_onebit = 1'b0;

reg [3:0] arb_priority = 4'b1011;

Verilog支持定义wire和reg的数组,支持一维数组和二维数组,但每次从数组中选择的元素不能超过一个,数组也不能作为任务或函数的传递参数。数组的定义示例如下:

//有32个元素的数组,每个元素4bits位宽

reg [3:0] mem_array [31:0];

//包含64个8bits位宽元素的数组

wire [7:0] mem_array [63:0];

//包含256*16个8bits位宽wire元素的二维数组

wire [63:0] array2 [0:255][0:15];

//包含256*8个64bits位宽reg元素的二维数组

reg [63:0] array2 [255:0][7:0];

Vivado支持的所有表达式列在下表中:

其中“===”和“!==”在综合时与“==”和“!=”功能相同,没有任何差别。但在仿真中,可以用来判断变量是否与’x’和’z’是否相等。下表给出常用操作符的运算结果,以供查阅:

initial和always是两个程序块,每个块内部组织了一些语法声明,用begin和end表示范围。块内部的语法声明按顺序执行。综合时只会处理always块,会忽略initial块 ;

8.模块module

Verilog中描述组件(component)的方法便是模块(module),模块必须申明与实例化。模块申明包括模块名称、电路I/O端口列表、定义功能的主体,并以endmodule结束;

每个电路I/O端口要有名称、端口模式(input、output、inout),如果端口是数组类型还要有范围信息。下面给出两种模块申明方法的示例:

//方法1

module example (A, B, O);

input A, B;

output O;

assign O = A & B;

endmodule

//方法2,推荐用法

module example

(

input A, B,

output O

);

assign O = A & B;

endmodule

实例化模块时,要定义一个实例化名称和一个端口关系表。列表要规定实例与顶层模块之间如何连接,列表中的每一个元素将模块申明中的一个形式端口(port)和顶层模块中的实际网络(net)连接在一起。下面给出一个实例化上述模块的例子:

module top

(

input A, B, C,

output O

);

wire tmp;

example inst_example (.A(A), .B(B), .O(tmp));//实例化

assign O = tmp | C;

endmodule

连续赋值 Continuous Assignments

连续赋值语句常用于组合逻辑中,在综合时vivado会忽略组合逻辑的延时和强度,并且连续赋值只能对wire和tri数据类型赋值;

直接连续赋值用assign关键词开头,紧跟一个已经申明过的网络:“wire mysignal; assign mysignal = select ? b : a;”;

简介连续赋值在申明时便完成赋值:“wire misignal = a | b;”;

9.Procedural Assignments 过程赋值

如上所述,wire和三态类型要用连续赋值,reg类型变量则需要用过程赋值,借助always块、任务(task)、函数(function)实现;

always块中的组合逻辑由Verilog时间控制语句有效地建模。其中,延迟时间控制语句[#]仅用于仿真,综合时会忽略;组合逻辑建模主要由事件控制时间控制语句[@]实现;

每个always块都有一个敏感列表,列在“always @”后面的括号中。如果敏感列表中一个信号的相关事件发生(值变化或边沿到来),就会激活该always块。在always块中,如果信号没有在if或case的所有分支中明确地赋值,综合会产生一个锁存器保持之前的值。一个程序块中可以使用如下语句:

[1] if-else:

使用true和false条件来执行语句,执行多条语句要使用begin…end关键词,注意在前面的分支优先级最高;示例如下:

module mux4 (sel, a, b, c, d, outmux);

input [1:0] sel;

input [1:0] a, b, c, d;

output [1:0] outmux;

reg [1:0] outmux;

always @(sel or a or b or c or d)

begin

if (sel[1])

if (sel[0])

outmux = d;

else

else

outmux = c;

if (sel[0])

outmux = b;

end endmodule

else

outmux = a;

[2] case:

比较表达式和分支的值,比较顺序按照编写分支的顺序进行,执行第一个匹配的分支,在前面的分支优先级最高;如果没有匹配项则执行default分支;case语句中不要使用未指定位宽大小的整数,否则可能会产生错误结果;

casez将分支的任意bit位上的z值视作不关心;casex将分支的任意bit位上的x值视作不关心;casez和casex中不关心的bit用‘?’代替;

下面给出一个使用case的示例代码:

module mux4

(

input [1:0] sel,

input [1:0] a, b, c, d,

output reg [1:0] outmux

);

always @ *

case(sel)

2'b00 : outmux = a;

2'b01 : outmux = b;

2'b10 : outmux = c;

2'b11 : outmux = d;

endcase

endmodule

上述代码在评估输入值时,按照一定的优先级顺序进行。如果希望能并行地处理这个过程,使用paralled_case属性,将case语句替换为“(* paralled_case *)” case(sel)”;

[3] For与Repeat:

For循环的边界必须是常数,停止循环条件需要使用>、<、>=、<=四种运算符。使用“var = var +或- step”来控制执行下一轮运算,var为循环变量,step是一个常数值;

repeat语句,重复次数也必须是常数值;

[4] While循环:

While的测试表达式可以是任意合法的Verilog表达式。为了避免造成无限循环,可以使用-loop_iteration_limit选项。该语法很少使用,下面给出一个示例代码:

parameter P = 4;

always @(ID_complete)

begin : UNIDENTIFIED

integer i;

reg found;

unidentified = 0;

i = 0;

found = 0;

while (!found && (i < P))

begin

found = !ID_complete[i];

unidentified[i] = !ID_complete[i];

i = i + 1;

end

end

[5] 顺序always块:

always块可以描述带有顺序性的电路,敏感列表中需要包含如下边沿触发事件(上升沿posedge或下降沿negedge):必须有一个时钟事件、可选的置位/复位事件。如果不需要异步信号,always块模板如下:

always @(posedge CLK)

begin

//同步部分

end

如果需要异步控制信号,always块模板如下:

always @(posedge CLK or posedge ACTRL1 )

begin

if (ACTRL1)

//异步部分

else

//同步部分

end

下面给出四个不同触发方式的顺序always块示例代码:

//上升沿触发时钟控制的8bits寄存器

module seq1

(

input [7:0]DI,

input CLK,

output reg [7:0] DO

);

always @(posedge CLK)

DO <= DI ;

endmodule

//添加一个高电平有效异步复位信号

module seq1

(

input [7:0]DI,

input CLK, ARST,

output reg [7:0] DO

);

always @(posedge CLK or posedge ARST)

if (ARST == 1'b1) DO <= 8'h00;

else DO <= DI ;

endmodule

//再添加一个低电平有效异步置位信号

module seq1

(

input [7:0]DI,

input CLK, ARST, ASET

output reg [7:0] DO

);

always @(posedge CLK or posedge ARST or negedge ASET)

if (ARST == 1'b1) DO <= 8'h00;

else if (ASET == 1'b1) DO <= 8'hFF;

else DO <= DI ;

endmodule

//不使用异步控制逻辑,使用同步复位

module seq1

(

input [7:0]DI,

input CLK, SRST,

output reg [7:0] DO

);

always @(posedge CLK)

if (SRST == 1'b1) DO <= 8'h00;

else DO <= DI ;

endmodule

最后再补充一些与赋值有关的内容。如果表达式左边位宽大于右边的位宽,赋值时需要在高位填充:

如果表达式右边为无符号数,则高位补0;

如果表达式右边为带符号数,则高位补符号位;

如果表达式右边的最高位为x或z,则无论该数为无符号数还是带符号数,高位都补充为x或z;

[6] Tasks and Functions 任务和函数

对于设计中要多次使用重复的代码,可以使用任务task和函数function来减少代码量,提升可维护性;

任务和函数必须在模块中申明和使用;

函数头只包含输入参数;

任务头包含输入、输出和双向参数;

函数的返回值可以申明为无符号数或带符号数,函数内容与always块类似;

下面分别给出一个函数和任务的示例代码:

//函数function使用示例

module test

(

input [3:0] A, B,

input CIN,

output [3:0] S,

output COUT

);

wire [1:0] S0, S1, S2, S3;

function signed [1:0] ADD;//输出

input A, B, CIN;//输入

reg S, COUT;

begin

S = A ^ B ^ CIN;

COUT = (A&B) | (A&CIN) | (B&CIN);

ADD = {COUT, S};

end

endfunction

assign S0 = ADD (A[0], B[0], CIN),//例化的时候只需要例化输入

S1 = ADD (A[1], B[1], S0[1]),

S2 = ADD (A[2], B[2], S1[1]),

S3 = ADD (A[3], B[3], S2[1]),

S = {S3[0], S2[0], S1[0], S0[0]},

COUT = S3[1];

endmodule

//任务task使用示例

module test

(

input [3:0] A, B,

input CIN,

output [3:0] S,

output COUT

);

reg [1:0] S0, S1, S2, S3;

task ADD;//ADD为task名称,这与上面的function不同

input A, B, CIN;//输入

output [1:0] C;//输出

reg [1:0] C;

reg S, COUT;

begin

S = A ^ B ^ CIN;

COUT = (A&B) | (A&CIN) | (B&CIN);

C = {COUT, S};

end

endtask

always @(A or B or CIN)

begin

ADD (A[0], B[0], CIN, S0);

ADD (A[1], B[1], S0[1], S1);

ADD (A[2], B[2], S1[1], S2);

ADD (A[3], B[3], S2[1], S3);

S = {S3[0], S2[0], S1[0], S0[0]};

COUT = S3[1];

end

endmodule

Verilog还支持递归任务和递归函数,要使用automatic关键词申明。递归次数由-recursion_iteration_limit选项设置,默认为64,以避免无限递归;下面给出一个计算阶乘的递归函数的例子:

function automatic [31:0] fac;

input [15:0] n;

if (n == 1) fac = 1;

else fac = n * fac(n-1);

endfunction

Vivado综合支持函数调用来计算常数值,将其称之为常数函数。下面给出一个使用常数函数的例子:

module test #(parameter ADDRWIDTH = 8, DATAWIDTH = 4)

(

input clk, we,

input [ADDRWIDTH-1:0] a,

input [DATAWIDTH-1:0] di,

output [DATAWIDTH-1:0] do

);

function integer getSize;

input addrwidth;

begin

getSize = 2**addrwidth;//2的次方

end

endfunction

reg [DATAWIDTH-1:0] ram [getSize(ADDRWIDTH)-1:0];

always @(posedge clk)

if (we) ram[a] <= di;

assign do = ram[a];

endmodule

Verilog中的常数可以用2进制、8进制、10进制和16进制表示,没有明确表示时默认为10进制;

11.Verilog宏

Verilog可以像这样定义宏“`define TESTEQ1 4’b1101”。定义的宏可以用在后面的代码中,如“if (request == `TESTEQ1)”。使用`ifdef和`endif可以检测是否定义了某个宏,相当于条件编译。如果`ifedf调用的宏被定义过,则内部的代码将会编译;如果宏没有定义,则会编译`else中的代码。`else不是必须的,但必须有`endif。

使用宏可以在不修改源代码的情况下修改设计,在IP核生成和流程测试中很有用。下面给出两个使用宏的例子:

//示例1

'define myzero 0

assign mysig = 'myzero;//注意要加宏符号

//示例2,条件编译

'ifdef MYVAR

module if_MYVAR_is_declared;

...

endmodule

'else

module if_MYVAR_is_not_declared;

...

endmodule

'endif

12 Include文件(不太理解)

Verilog可以将源代码分散在多个文件中,当需要引用另一个文件中的代码时,可以使用如下语句:“`include <path/file-to-be-included>”。该代码可以将指定文件的内容全部插入到当前文件的`include行中。Vivado首先会在指定路径中查找,如果没有找到则会在-include_dirs选项设置的目录中查找。可以同时使用多个`include语句

13 Generate

使用generate可以简化代码编写工作,generate…endgenerate中的内容再RTL分析阶段会被转换为对应的电路;

使用generate语法可以创建原语或模块实例、initial或always程序块、连续赋值、网络和变量申明、参数重定义、任务或函数定义。Vivado支持全部三种generate语法:generate循环(generate-for)、generate条件(generate-if-else)和generate情况(generate-case);

[1] generate-for

使用generate-for主要用来创建多个实例化,与for循环用法基本相同,但必须使用genvar变量,且begin语句必须有一个单独的命名;下面给出一个示例代码:

generate genvar i;

for (i=0; i<=7; i=i+1)

begin : for_name

adder add (a[8*i+7 : 8*i], b[8*i+7 : 8*i], ci[i], sum_for[8*i+7 : 8*i],

c0_or[i+1]);

end

endgenerate

[2] generate-if-else

主要用来控制生成哪一个对象,每一个分支用begin…end限定,begin语句必须有一个单独的命名;下面给出一个示例代码:

//根据数据位宽选择不同的乘法器实现方式

generate

if (IF_WIDTH < 10)

begin : if_name

multiplier_imp1 # (IF_WIDTH) u1 (a, b, sum_if);

end

else

begin : else_name

multiplier_imp2 # (IF_WIDTH) u2 (a, b, sum_if);

end

endgenerate

[3] generate-case

主要用来控制在哪种条件下生成哪个对象。case的每一个分支用begin…end限定,begin语句必须有一个单独的命名;下面给出一个示例代码:

generate

case (WIDTH)

1:

begin : case1_name

adder #(WIDTH*8) x1 (a, b, ci, sum_case, c0_case);

end

2:

begin : case2_name

adder #(WIDTH*4) x2 (a, b, ci, sum_case, c0_case);

end default:

begin : d_case_name

adder x3 (a, b, ci, sum_case, c0_case);

end

endcase

endgenerate

什么?DNA也能做成芯片了?

100多年前,英国数学家艾伦·图灵(Alan Turing)的图灵机为现代计算奠定了基础,而到现在,人类也一直在基本同样原理下研究芯片。

一百年后的今天,摩尔定律开始放缓,人们的目光放到了同样处在微观世界的DNA身上,并悄悄地把它放在电子技术的新赛道上。

付斌|作者

电子工程世界(ID:EEworldbbs)|出品

初创公司推出DNA存储卡

最近,一家名为Biomemory的法国初创公司推出全球首款DNA存储卡(DNA Cards),可存储1KB数据。

别看它存储容量小,可这款DNA存储卡的数据可保存至少150年,远超任何人的寿命。不过,这样“过于超前”的产品,售价达到了惊人的1000欧元。

20世纪80年代,Biomemory科学家们首次在法国使用的嵌入微芯片的信用卡中汲取灵感,设计了一种类似银色信用卡的设备,其中有一个圆形芯片,可以保存干燥的DNA。为保存DNA,卡被密封以防止任何氧气进入。

对于这个产品的下一步,Biomemory将扩大设备的容量,以容纳家庭照片、重要文档、音频和视频文件。并计划将存储时间延长到1000年,最终延长到10000年。由于DNA是在溶液中合成,因此下一步是将其干燥以延长其保质期。

当然,Biomemory显然明白对于普通人来说,花1000欧元存1KB数据对大多数人并不现实,因此该公司计划在2026年推出“Biomemory Prime”数据中心存储解决方案,可存储 100PB 数据。

不过,这也仅仅是最乐观的预期,毕竟这项技术还比较年轻,相比来说,排在它前面的还有玻璃或陶瓷存储技术。

用200公斤装下“整个世界”

DNA做成存储器,其实是一个“意外”。事实上,原本科学家事为生命科学应用而开发的DNA合成、测序和检索技术。相比传统的存储介质,DNA在信息保留时间、物理密度和体积编码容量方面都有着优势,但我们的技术还没有那么成熟。

互联网巨头微软也曾踏足这个领域,2017年,微软组建了特别技术小组,负责研发基于DNA编码技术的数据存储系统,彼时微软表示,在未来三年内,旨在研发出测试版“微缩型DNA生物存储器”。DNA容量最大且可塑性极强,能够解决爆炸式增长的数据信息与存储空间和技术不匹配的问题。

这些DNA生物存储器或许会成为每个人特制的“数据细胞器”,把全球所有电影、视频录像、照片和有价值的文档存储在每个人的DNA基因编码里,之所以能够实现这样的技术,基础在于基因编辑技术CRISPR-Cas9已趋于成熟了。

2019年,微软和华盛顿大学的研究人员又推进了DNA存储技术的发展。而后,微软还联合哈佛大学、华盛顿大学等曾一起成立了DNA数据存储联盟,推动DNA存储发展。

值得强调的是,DNA存储是国家“十四五”科技规划中明确提出要加快布局的前沿技术之一。而在美国《科学》杂志提出了未来125个科学问题中,DNA存储也是重点。

为什么大家如此关注DNA存储?这是因为数据正在以爆炸式速度增长,到2025年全球数据量会达到1750万亿字节,这些数据能耗巨大,传输体积也巨大,其中80%~90%极少被调用的“冷数据”。而且更为关键的是,信息存储在硅上,寿命大约是数十年。

DNA存储不仅密度高、能耗低,而且寿命长,能稳定保存百年、千年,极端条件下甚至可达百万年。举个例子来说,1000万块硬盘的数据,用50克的DNA就可以存储下来,而全世界440万亿字节的数据用200公斤DNA就可以存下来。

当然,这一切都是在理论中,这种技术多久才能面世,才能具备商业价值,都还是未知数。

国内轰动一时的研究

DNA是生物体内的遗传信息载体,其中腺嘌呤(A)、胸腺嘧啶(T)、鸟嘌呤(G) 和胞嘧啶(C)4种含氮碱基按特定顺序排列以编码遗传信息。大自然,是否也遵循着什么编码规则?我们不得而知,但这样看,似乎与数学和程序有着很大的关系,科学家也从中找到了很大灵感。

1994年Adleman首先提出DNA计算模型的概念,他利用DNA碱基互补配对原则的热力学平衡过程构建了模型,以计算哈密尔顿路径问题,并取得了成功。

2004年,Okamoto等3位学者首次将数字电路与DNA计算相结合,构建DNA电路,并形成DNA逻辑门,即将不同级逻辑门通过级联的形式组成复杂的电路,最终实现通用的DNA计算,为DNA计算和组装技术实现新一代芯片组装提供了理论基础。

2009年,IBM利用DNA和纳米技术开发下一代微处理芯片,开创了DNA计算的新时代。此时,DNA计算已经具备一定战略性意义。

2023年底,海交通大学樊春海院士、王飞副教授团队一篇刊上Nature的论文也引发了巨大讨论,这标志着中国已经成功DNA计算领域取得重要进展。

DNA计算机依赖的不再是硅晶片,而是大自然数十亿年来用以编码生命蓝图的分子。这类计算机通过实验室操作来执行计算,并以DNA链式形式的数据作为输入和输出。

研究者通过集成支持通用性计算的多层DNA可编程门阵列(DPGA, DNA-based programmable gate array),展示了一种DNA集成电路(DIC)。他们发现,使用通用的单链寡核苷酸作为统一的传输信号,可以可靠地集成大规模DIC,并能最小化泄露,实现高保真度。此外对具有24个可寻址双轨门的单个DPGA进行重新配置,可以运行超过1000亿个不同的电路。

此外,为了控制分子本质上的随机碰撞,研究者设计了DNA折纸寄存器,为级联DPGA的异步执行提供了方向。他们通过三层级联DPGA(包含30个逻辑门、约500个DNA 链)组装而成的二次方程求解DIC证明了这一点。

研究者进一步证明,DPGA与模数转换器的集成可以对与疾病相关的microRNA进行分类。无明显信号衰减下集成大规模DPGA网络,这标志着迈向通用DNA计算的关键一步。

在试管里完成运算

与常规计算机相比,DNA计算潜力无限,它具有高并行、低能耗的优势。理论上,DNA每平方毫米最多可以存储1艾字节(exabyte)或10亿千兆字节。不仅如此,一滴水就能容纳数万亿DNA分子,这表明DNA计算能够并行执行海量计算的同时,只需要很少的能量。

科学家发现,DNA在一个试管里,一步就能完成1020次运算。一些电子计算机不能计算的问题,比如哈密尔顿路径问题,就可能通过DNA计算机来完成。DNA计算在未来的科学领域中,有望在优化计算、密码学、数学等领域取得突破性的创新和应用。

那么DNA是怎么计算的?它本质是利用大量不同核酸分子杂交,产生类似数学计算过程中某种组合的结果,并且根据限制条件得出约束解。

与传统的芯片蕾丝,DNA计算是由传统意义的“电路”构成的,不过这些电路是特定功能的DNA链构成的DNA电路,DNA电路中不使用任何类型的电压和电流,电路信号是DNA链的浓度或DNA链中特定片段的有无。

相比传统计算机,DNA计算机并行计算能力强,也就是说DNA可以像GPU一样,同时计算大量内容,同时DNA计算具有非常高的能量效率和存储容量。

值得一提的是,DNA不仅能实现数字电路,还能实现模拟电路。

数字电路方面,AND、OR、XOR、NOT、NAND、NOR和XNOR这些逻辑门是关键,DNA计算则以DNA链浓度作为信号,浓度高于特定阈值,则认为该信号为逻辑高,否则为逻辑低,有点类似高电平、低电平。

根据这种原理,Nielsen曾经参考FPGA的编码方式进行设计了一个自动化设计基因电路的平台Cello,设计编码方式与Verilog相似。科学家们也把这种器件叫做DPGA(高度可扩展的基于DNA的可编程门阵列,DNA-based programmable gate arrays,DPGAs)。

模拟电路方面,输入和输出信号通常用分子浓度来表示,即模拟DNA元件能够感知特定分子在具体环境中的浓度,然后通过适当的模拟计算产生固定浓度的输出信号。模拟电路中最基础的元件是晶体管,但是DNA电路无法转变为DNA晶体管电路,因此在DNA模拟电路中在行为层面上将模拟电子电路映射到模拟DNA电路。目前,科学家已经利用DNA实现了反馈控制电路、决策器、神经生物学的模数转换和数模转换等。

需要强调的是,尽管DNA计算被证实是通用计算,但DNA计算在实际应用中无法取代电子计算,最优方案是利用DNA计算实现高度并行任务,而固有的串行任务仍采用电子计算完成。同时,DNA计算发展有三方面障碍:

对大规模系统进行物理处理时会产生错误;在PCR扩增环节存在基因突变的问题;目前在浓度检测过程中缺少快捷高效的检测仪器。

随着生物技术不断进步,DNA越来越被人“玩出花”,随着电子技术逐渐产生瓶颈,学科交叉成了越来越领域突破瓶颈的关键。

相关问答

Verilog hdl中always@(negedgeclrnorposedgeclk)是什么意思?a...

[最佳回答]呵呵,clrn和clk都是你自己定义的信号.clk一般是时钟信号,clrn就不太容易猜了.这句话的意思是每当clrn信号的下降沿,或者clk的上升沿是,就开始执行a...

 htc t528w  飞鸽传信 
王经理: 180-0000-0000(微信同号)
10086@qq.com
北京海淀区西三旗街道国际大厦08A座
©2024  上海羊羽卓进出口贸易有限公司  版权所有.All Rights Reserved.  |  程序由Z-BlogPHP强力驱动
网站首页
电话咨询
微信号

QQ

在线咨询真诚为您提供专业解答服务

热线

188-0000-0000
专属服务热线

微信

二维码扫一扫微信交流
顶部