秒的换算
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,fork,join,initial,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可以去除这种效果,使得每次选择该条命令时必执行。后续的语句即为常规语句。