日常记录(6)Verilog

2021-12-14 15:22:08 浏览数 (1)

秒的换算

https://baike.baidu.com/item/秒/2924586

1s=10^3ms(毫秒)=10^6μs(微秒)=10^9ns(纳秒)=10^12ps(皮秒)=10^15fs(飞秒)=10^18as(阿秒)=10^21zm(仄秒)=10^24ym(幺秒)

时间单位1ns,10fs精度

代码语言:javascript复制
`timescale 1ns/10fs

不可综合

https://www.cnblogs.com/jiu0821/p/4166192.html

1)所有综合工具都支持的结构:always,assign,begin,end,case,wire,tri,aupply0,supply1,reg,integer,default,for,function,and,nand,or,nor,xor,xnor,buf,not,bufif0,bufif1,notif0,notif1,if,inout,input,instantitation,module,negedge,posedge,operators,output,parameter。 2)所有综合工具都不支持的结构:time,defparam,$finish,forkjoininitial,delays,UDP,wait。 3)有些工具支持有些工具不支持的结构:casex,casez,wand,triand,wor,trior,real,disable,forever,arrays,memories,repeat,task,while。 建立可综合模型的原则 要保证Verilog HDL赋值语句的可综合性,在建模时应注意以下要点:

(1)不使用initial。

(2)不使用#10。

(3)不使用循环次数不确定的循环语句,如forever、while等。

(4)不使用用户自定义原语(UDP元件)

(5)尽量使用同步方式设计电路。

(8)所有的内部寄存器都应该能够被复位,在使用FPGA实现设计时,应尽量使用器件的全局复位端作为系统总的复位。

(12)避免混合使用上升沿和下降沿触发的触发器。 不可综合verilog语句 1、initial

2、events

3、real

4、time

5、force 和release

6、assign 和deassign 不支持对reg 数据类型的assign或deassign进行综合,支持对wire数据类型的assign或deassign进行综合。

7、fork join 不可综合,可以使用非块语句达到同样的效果。

8、primitives 支持门级原语的综合,不支持非门级原语的综合。

9、table 不支持UDP 和table的综合。 10、敏感列表里同时带有posedge和negedge always @(posedge clk or negedge clk) begin...end 这个always块不可综合。 11、同一个reg变量被多个always块驱动

12、延时以#开头的延时不可综合成硬件电路延时,综合工具会忽略所有延时代码,但不会报错。

如:a=#10 b; 这里的#10是用于仿真时的延时,在综合的时候综合工具会忽略它。也就是说,在综合的时候上式等同于a=b;

13、与X、Z的比较

惯性延时和传输延时

@和wait的区别

两个概念,但是还有点相同的地方。主要是用法的差异。@应该是某时刻点的一种触发,wait似乎是等待一段时间。

在竞争关系中,使用wait可以缓解事件偶尔未被触发。

https://blog.csdn.net/qq_41894346/article/details/104964478

在Verilog中当一个线程在一个事件上发生阻塞的同时,正好另一个线程触发了这个事件,则竞争就出现了。如果触发线程先于阻塞线程,则触发无效(触发是一个零宽度的脉冲)。

Systemverilog 引入了triggered()函数,用于检测某个事件是否已被触发过,包括正在触发。线程可以等待这个结果。

代码语言:javascript复制
event a;    //使用关键字event来声明一个事件a
initial begin
    #1;
    ->a;
end
initial    begin
    #1;
    @a;        //第一个进程在1ns后触发了事件a,那么第二个进程在1ns的时候等待a,有可能等的到,有可能等不到,产生竞争
end
initial begin
    #1;
    wait(a.triggered); //使用wait来等待事件a,这种方式是一定可以等到a的,这是和使用@来等待的区别
end

例子2

https://blog.csdn.net/Michael177/article/details/120807670

triggered()函数,用于检测某个事件是否已被触发过,包括正在触发。线程可以等待这个结果,而不用在@操作符上xx

代码语言:javascript复制
module event_test();
  event a;
  initial begin
    #50;
    ->a;
    $display("Event a is being triggered!");
  end
  
  initial begin
    #20;
    wait(a.triggered);
    $display("#20 a.triggered!");
  end
  
  initial begin
    #50;
    wait(a.triggered);
    $display("#50 a.triggered!");
  end
  
  initial begin
    #60;
    wait(a.triggered);
    $display("#60 a.triggered!");
  end

endmodule

parameter、interger、reg

https://blog.csdn.net/wuguozeng1989/article/details/46682125

1. integer类型的变量作为有符号数使用,而reg类型的变量则作为无符号数使用。

2. integer的位宽为字的位数,最小为32位

https://blog.csdn.net/qq_16923717/article/details/81067096

3. parameter是常量,不是变量,所以不允许在运行时修改它的值,即不能在组合逻辑或者时序逻辑中对其进行赋值。

竞争与冒险

https://blog.csdn.net/wordwarwordwar/article/details/79829130

信号由于经由不同路径传输达到某一汇合点的时间有先有后的现象,就称之为竞争,英文名Race;

由于竞争现象所引起的电路输出发生瞬间错误的现象,就称之为冒险,英文名Hazard或者Risk。

有竞争不一定有冒险,但出现了冒险就一定存在竞争。

解决方式:

1.引入封锁脉冲,锁存器

2.引入选通脉冲,稳定后选择

3.引入滤波电容。

4.修改逻辑设计。

https://blog.csdn.net/yc16032399/article/details/100126361

RS锁存器

https://blog.csdn.net/kewei168/article/details/101141511

真值表

R

S

Q

0

0

Q

0

1

1

1

0

0

1

1

X

  • R=1时,S=0,输出为0,故R又称为直接置“0”端,或“复位”端
  • 当R=0时,S=1,输出为1,故S又称为直接置“1”端,或“置位”端
  • 当R=S=0时,输出保持不变(保证了RS同时为0(断电)后,电路输出能够保持不变)
  • RS同时为1,若从同时为0的状态开始变化,则中间产生不定的输入状态01或10,产生不定的输出,不被使用。

Makefile

Makefile拆分为两部分,进行逐个解释。

(1)第一部分如下

代码语言:javascript复制
CC=g  

sources:=$(wildcard *.c) $(wildcard *.cpp)

objects:=$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(sources)))

dependence:=$(objects:.o=.d)

all: $(objects)

    $(CC) $(CPPFLAGS) $^ -o $@

    @./$@  

%.o: %.c

    $(CC) $(CPPFLAGS) -c $< -o $@

%.o: %.cpp

    $(CC) $(CPPFLAGS) -c $< -o $@
代码语言:javascript复制
wildcard表示通配符,source则是整个文件夹中所有的c文件和h文件组成的变量。patsubst表示替换,%表示任意。首先将source变量中的所有cpp文件名转换为o文件名,然后再将修改后的变量中,所有的c文件名转换为o文件名,最后组成object变量。下一行的等号表示替换关系,将object中的所有.o文件名替换为.d文件名,组成了dependence文件名变量。make默认执行第一个规则,第一个规则名为all,其依赖了所有的object,即该文件夹下的所有.o文件。在执行该条语句前,应该先执行所有的.o对应的规则,当所有的.o的规则满足后,则执行编译过程。其中的$^表示了本条规则下所有依赖的文件名,$@表示本条编译规则名称,即all。当执行本条命令,则会生成一个名称为all的可执行文件。之后的@表示不显示执行的该条命令(当执行make时,所有执行的实际命令会在屏幕中进行打印)。 CC为编译器,使用=表示延迟生效的变量,使用:=表示立即生效的变量。延时生效的变量使用意义在于,随后对CC进行重新赋值后,以重新赋值的结果在整个Makefile中生效。

%.o:%.c表示当前的文件夹下的每个.o文件方法,都依赖于每个对应的.c文件。然后执行生成过程。生成过程中,使用$<表示该方法依赖的文件中的第一个(因为有些时候依赖的内容不仅包括.c文件,还包括.h文件,.h文件一般不会写在第一个位置)。

(2)第二部分如下

代码语言:javascript复制
include $(dependence)  

define gen_dep

set -e; rm -f $@; 

$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; 

sed 's,($*).o[ :]*,1.o $@ : ,g' < $@.$$$$ > $@

rm -f $@.$$$$

endef

%.d: %.c

    $(gen_dep)

%.d: %.cpp

    $(gen_dep)

.PHONY: clean

clean: 

    rm -f all $(objects) $(dependence)

echo:  

    @echo sources=$(sources)

    @echo objects=$(objects)

    @echo dependence=$(dependence)

    @echo CPPFLAGS=$(CPPFLAGS)
代码语言:javascript复制
使用define和endef的宏定义,以gen_dep代表随后的4行命令。set -e,这句语句告诉bash如果任何语句的执行结果不是true则应该退出,而不是继续向下执行。rm -rf $@表示删除生成的目标文件。 include表示引入外部文件,原理上类似于C语言中的.c文件。这里将所有的.d文件规则进行展开。写到这里而不是开头的原因在于,开头写的规则为默认规则,写到开头会覆盖默认规则。

-M显示完整的c文件对头文件依赖关系,一般使用-MM显示不包含系统头文件的部分即可。>符号表示数据重定向符号,将数据重定向到$@.$$$$文件。在Makefile文件中,$表示变量的标记,使用$$则为真正的$符号。四个$转换为两个$符号,两个$符号表示进程的pid。因此数据会重定向到一个后缀为.pid的对应文件中。

sed的替换命令中,使用逗号作为分隔符,s,g作为开头和结尾,中间添加逗号,进行行内替换操作。$*匹配%.d中的%表示的部分,即为规则目标使用通配符时,通配符表示的数据的第一部分。然后外部添加括号和.o,并添加数个空格和冒号,作为替换的源。该正则表达式分为三部分,以括号为第一部分,.o为第二部分,[ :]*为第三部分。

在替换的目标中,1表示替换的源的第一部分,然后添加.o和空格和该规则下的先决条件名。替换的结果存储在目标文件中。sed将上一句生成的依赖关系中的一些部分进行了替换,写入到了每个先决条件文件下。替换的内容为:target.o : target.c *.h替换为:target.o target.d : target.c *.h。每个target.d文件的生成依赖于对应的target.c和*.h文件。当.d文件发生变化,则执行对应的make规则。即.d文件表达了替换名。

随后的%d:%c以及%d:%cpp则对应执行了需要的命令。.d文件若是最新的,则.d对应的规则不会被执行。clean也是一样。当目录下存在一个为clean的文件,则对应的规则不会被执行。使用.PHONY可以去除这种效果,使得每次选择该条命令时必执行。后续的语句即为常规语句。

0 人点赞