新人报道,分享些自己的笔记。
世纪伯乐2013/06/11电子技术 IP:河南
初来乍到,貌似要有高质量贴才能不被删号,就分享一下自己曾经的笔记吧。
希望下面看的朋友等我发完再回复,插楼可耻。。。
+23  科创币    kc地毯清洁员    2013/06/11 有原文件下载吗
来自:电子信息 / 电子技术
16
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
世纪伯乐 作者
11年7个月前 IP:未同步
534708
先分享下自己的Verilog笔记吧。因为不是一个时期写的,有些凌乱。
绪论:
1、什么是信号处理电路?它通常由哪两大部分组成?
  信号处理电路是进行一些复杂的数字运算和数据处理,并且又有实时相应要求的电路。它通常有高速数据通道接口和高速算法两大部分组成。
  
为什么要设计专用的信号处理电路?
  因为有的数字信号处理对时间的要求非常苛刻,以至于用高速的通用处理器也无法在规定的时间内完成必要的运算。通用微处理器芯片是为一般目的而设计的,运算的步骤必须通过程序编译后生成的机器码指令加载到存储器中,然后在微处理器芯片控制下,按时钟的节拍,逐条取出指令分析指令和执行指令,直到程序的结束。微处理器芯片中的内部总线和运算部件也是为通用目的而设计,即使是为信号处理而设计的通用微处理器,因为它的通用性也不可能为某一特殊的算法来设计一系列的专用的运算电路而且其内部总线的宽度也不能随便的改变,只有通过改变程序,才能实现这个特殊的算法,因为其算法速度也受到限制所以要设计专用的信号处理电路。
  
为什么是实时处理系统?
  实时处理系统是具有实时相应的处理系统。

为什么要用硬件描述语言来设计复杂的算法逻辑电路?
  因为现代复杂数字逻辑系统的设计都是借助于EDA工具完成的,无论电路系统的方针和综合都需要掌握硬件描述语言。
  
能不能完全用C语言来代替硬件描述语言进行算法逻辑电路的设计?
  不能,因为基础算法的描述和验证通常用C语言来做。如果要设计一个专用的电路来进行这种对速度有要求的实时数据处理,除了以上C语言外,还需用硬件描述语言程序进行仿真以便从电路结构上保证算法能在规定的时间内完成,并能通过与前端和后端的设备接口正确无误的交换数据。
  
为什么在算法逻辑电路的设计中需要用C语言和硬件描述语言配合使用来提高设计效率?
  首先C语言很灵活,查错功能强,还可以通过PLI编写自己的系统任务,并直接与硬件仿真器结合使用。C语言是目前世界上应用最为广泛的一种编程语言,因而C程序的设计环境比Verilog HDL更完整,此外,C语言有可靠的编译环境,语法完备,缺陷较少,应用于许多的领域。比较起来,Verilog语言只是针对硬件描述的,在别处使用并不方便。而用Verilog的仿真,综合,查错等大部分软件都是商业软件,与C语言相比缺乏长期大量的使用,可靠性较差,亦有很多缺陷。所以只有在C语言的配合使用下,Verilog才能更好的发挥作用。C语言与Verilog HDL语言相辅相成,互相配合使用。这就是即利用C语言的完整性又要结合Verilog对硬件描述的精确性,来更快更好地设计出符合性能要求的硬件电路,从而来提高效率。
  

什么是硬件描述语言?它的主要作用是什么?
  硬件描述语言是一种用形式化方式来描述数字电路和系统的语言。它的主要作用是:数字电路系统的设计者利用这种语言可以从上层到下层(从抽象到具体)逐步描述自己的设计思想,用一系列分层次的模块来表示极其复杂的数字系统。
  
目前世界上符合IEEE标准的硬件描述语言有哪两种?它们各有什么特点?
  符合IEEE标准的硬件描述语言是Verilog HDL和VHDL两种。它们的共同特点是:能够形式化地抽象表示电路的行为和结构;支持逻辑设计中层次与范围的描述:可借用高级语言的精巧结构来简化电路行为的描述:具有电路仿真与验证机制以保证设计的正确性;支持电路描述由高层到低层的综合转换硬件描述与实现工艺无关;便于文档管理;易于理解和设计重用。不同点:Verilog HDL是一种非常容易掌握的硬件描述语言,而VHDL掌握起来就比较困难。
  
什么情况下需要采用硬件描述语言的设计方法?
  在对逻辑电路及系统的设计的时间要求很短的情况下需要采用硬件描述语言的设计方法。
  
采用硬件描述语言设计方法的优点是什么?有什么缺点?
  优点是:与工艺无关性。这使得工程师在功能设计,逻辑验证阶段,可以不必过多考虑门级及工艺实现的具体细节,只需要利用系统设计时对芯片的要求,施加不同的约束条件,即可设计出实际电路。
  缺点是:需要相应的EDA工具,而EDA工具的稳定性需要进一步的在工程中提升。
  
简单叙述一下利用EDA工具并采用硬件描述语言的设计方法和流程?
  采用自顶向下的设计方法:从系统级开始把系统划分为基本单元,然后再把每个基本单元划分为下一层次的基本单元,一直这样做下去,直到可以直接用EDA元件库中的基本元件来实现为止。其基本流程主要由两大主要功能部分组成:(1)设计开发,即从编写设计文件—〉综合到布局布线—〉电路生成这样一序列步骤。(2)设计验证,也就是进行各种仿真的一序列步骤,如果在仿真过程中发现问题就返回设计输入进行修改。
  
硬件描述语言可以用哪两种方式参与复杂数字电路的设计?
  复杂数字电路的设计和复杂数字电路的仿真验证。
  
用硬件描述语言设计的数字系统需要经过哪些步骤才能与具体的电路相对应?
  编写设计文件;功能仿真;优化;布局布线;布线后门级仿真。
  
为什么说用硬件描述语言设计的数字逻辑系统下具有很大的灵活性并可以映射到任何工艺的电路上?
  硬件描述语言的设计具有与工艺无关性。这使得工程师在功能设计,逻辑验证阶段,可以不必过多考虑门级及工艺实现的具体细节,只需要利用系统设计时对芯片的要求,施加不同的约束条件,即可设计出实际电路。
  
软核是什么?虚拟器件是什么?它们的作用是什么?
  把功能经过验证的,可综合的,实现后电路结构总门数在5000门以上的Verilog HDL模型称为软核。而把由软核构成的器件称为虚拟器件。
  作用:大大缩短设计周期,加快复杂电路的设计。
  
集成电路行业中IP的含义是什么?固核是什么?硬核是什么?与软核相比它们各有什么特点?各适合于什么场合?
  在集成电路行业中IP是知识产权(intellectual property)的含义。把在某一现场可编程门阵列器件上实现的经验是正确的,总门数在5000门以上的电路结构编码文件称为固核。把在某一专用集成电路工艺的器件上实现的经验证实正确的总门数在5000门以上的门电路结构版图掩模成为硬核。
  在工具实现手段和工艺技术尚未确定的逻辑设计阶段,IP核具有很大的灵活性,很容易借助EDA工具与其他外部逻辑结合为一体。相比之下固核核硬核与其他外部逻辑结合为一体的灵活性要差很多。
  
简述Top_Down设计方法和硬件描述语言的关系?
  Top_Down的设计方法是首先从系统设计入手,从顶层进行功能划分和结构设计。系统的总仿真是顶层进行功能划分的总要环节,而该过程需要采用硬件描述语言的方法。
  
System Verilog与Verilog有什么关系?适合于何种设计?
  System Verilog是Verilog语言的拓展和延伸。Verilog适合系统级,算法级,寄存器级,逻辑级,门级,电路开关级设计而System Verilog更适合于可重用的可综合IP和可重用的验证用IP设计,以及特大型基于IP的系统级设计和验证。
  

Verilog语言有什么用?
  可描述顺序执行和并行执行的程序结构;用延迟表达式或事件表达式来明确地控制过程的启动时间;通过命名的事件来触发其他过程里的激活行为或停止行为;提供了条件如if-else,case等循环程序结构;提供了可定义新的操作符的函数结构;提供了用于建立表达式的算术运算符,逻辑运算符,位运算符;Verilog HDL语言作为一种结构化的语言非常适用于门级和开关级的模型设计;提供了一套完整的表示组合逻辑的基本元件的原话;提供了双向通路和电阻期间的原话;可建立MOS器件的电荷分享和电荷衰减动态模型;Verilog HDL的构造型语句可以精确地建立信号的模型;
  
构成模块的关键词是什么?
  module,endmodule
  
为什么说可以用Verilog构成非常复杂的电路结构?
    因为Verilog可描述顺序执行和并行执行的程序结构;用延迟表达式或事件表达式来明确地控制过程的启动时间;通过命名的事件来触发其他过程里的激活行为或停止行为;提供了条件如if-else,case等循环程序结构;提供了可定义新的操作符的函数结构;提供了用于建立表达式的算术运算符,逻辑运算符,位运算符;Verilog HDL语言作为一种结构化的语言非常适用于门级和开关级的模型设计;提供了一套完整的表示组合逻辑的基本元件的原话;提供了双向通路和电阻期间的原话;可建立MOS器件的电荷分享和电荷衰减动态模型;Verilog HDL的构造型语句可以精确地建立信号的模型;

为什么可以用比较抽象的描述来设计具体的电路设计?
  因为有可以用比较抽象描述设计电路结构的语言,而这种语言是适合数字系统设计的语言。
  
是否任意抽象的符合语法的Verilog模块都可以通过综合工具转变为电路结构?
  不能。要符合语法,还要符合一些基本的Verilog模块才可以通过综合工具转变为电路结构。
  
什么叫综合?
  通过综合工具把行为级描述的模块通过逻辑网表自动转化为门级形式的模块叫综合。
  
综合是由什么工具来完成的?
  EDA工具来完成综合的。
  
通过综合产生的是什么?产生的结果有什么用处?
  产生的是由与门,或门和非门组成的加法器,比较器等组合逻辑。产生的模块很容易与某种工艺的基本元件逐一对应起来,再通过布局布线工具自动地转变为某种工具工艺的电路布线结构。
  
仿真是什么?为什么要进行仿真?
  仿真是对电路模块进行动态的全面测试。通过观测被测试模块的输出信号是否符合要求可以调试和验证逻辑系统的设计和结构准确与否,并发现问题及时修改。
  
仿真可以在几层面上进行?每个层面的仿真有什么意义?
  分别为:前仿真,逻辑网表仿真,门级仿真和布线后仿真;
  前仿真,逻辑网表仿真,门级仿真,可以调试和验证逻辑系统的设计和结构准确与否,并发现问题及时修改。
  布线后仿真:分析设计的电路模块的运行是否正常。
  
模块的端口是如何描述的?
  用“.”表示被引用模块的端口。
  
在引用实例模块的时候,如何在主模块中连接信号线?
  用小括号中来表示本模块中与之链接的模块。
  
如何产生连续的周期性测试时钟?
  用always语句来产生连续的周期性测试模块。
  
如果不用initial块,能否产生测试时钟?
  不能,没有initial块,就不知道时钟信号的初始值。
  
从本讲中的简单例子,是否能明白always块与initial块有什么不同?
  Initial块只执行一次,而always块执行无数次。
  
为什么说Verilog可以用来设计数字逻辑电路和系统?
因为Verilog可描述顺序执行和并行执行的程序结构;用延迟表达式或事件表达式来明确地控制过程的启动时间;通过命名的事件来触发其他过程里的激活行为或停止行为;提供了条件如if-else,case等循环程序结构;提供了可定义新的操作符的函数结构;提供了用于建立表达式的算术运算符,逻辑运算符,位运算符;Verilog HDL语言作为一种结构化的语言非常适用于门级和开关级的模型设计;提供了一套完整的表示组合逻辑的基本元件的原话;提供了双向通路和电阻期间的原话;可建立MOS器件的电荷分享和电荷衰减动态模型;Verilog HDL的构造型语句可以精确地建立信号的模型;
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
534710

怎样理解initial语句只执行一次的概念?
在仿真开始时,initial语句只执行一次,但initial语句里面的语句可能不执行一次,因为如果是while循环,虽然initial语句是执行一次,但是只要进了while循环,则会执行到仿真结束。
在initial语句引导的过程中是否可以有循环语句?如果可以,是否与思考题1,互相矛盾?
可以,不矛盾。initial语句确实是只执行了一次,但并不意味着initial语句过程中就不能是循环语句,两者并不矛盾。
怎样理解由always语句引导的过程块是不断活动的?always语句的过程块是不断活动的,在仿真过程中always块始终在循环的活动着,检查always语句后面的信号是否发生相应改变,这是always活动的实质,如果always语句后面没有检查的信号则将会进入一个循环,将会使仿真器锁死。
不断活动与不断执行有什么不同?
不断活动是always语句不断活动,检查是否满足条件(如某个信号发生改变),不断执行时always语句引导的过程中的语句不断的执行着。
怎样理解沿触发和电平触发的不同?
沿触发式在某个信号在上升沿或下降沿到来时,触发执行过程块。电平触发式在某个信号发生改变时就会触发执行过程块。
是不是可以说沿触发是有间隔的,在一定的时间区间里只需要注意有限的点,而电平触发却需要注意无穷多个点?
不是。沿触发是信号的上升沿或下降沿进行触发,而电平触发式在某个信号发生改变时进行触发,并不需要注意无穷多个点。
沿触发的always快和电平触发的always块各表示什么类型的逻辑电路的行为?为什么?
沿触发的always块常表示时序逻辑电路,因为其和时序有关。电平触发的always块常表示组合逻辑电路,因为其只和电平有关。
简单叙述任务和函数的不同点
函数只能与主模块共用同一个仿真时间单元,而任务可以定义自己的仿真时间单位;
函数不能启动任务,而任务能启动其它任务和函数;
函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量;
函数返回一个值,而任务则不返回值。
简单叙述$display,$write和$strobe的不同点。
$display自动地在输出后进行换行,$write则不进行自动换行,其它都非常相似,如果许多其它语句与$display任务在同一个时间单位执行,那么现些语句与$display任务的执行顺序是不确定的。如果使用$strobe,该语句总是在同时刻的其它赋值语句执行完成后执行。
简单叙述语法规定的电平敏感列表的简化写法。
关键词“or”可以用“,”代替。
如果在Verilog测试模块中,利用文件的读写产生预定格式的信号,并记录有测试价值的信号?
Verilog提供了系统任务来选择要转储的模块实例或模块实例信号($dumpvars),选择VCD文件的名称($dumpfile),选择转储过程的起点和终点($dumpon,$dumpoff),选择生成检测点($dumpall),每个任务的使用方法。例:

initial
  $dumpfile ("XXXXXXXXXp");
  //仿真信息转储到XXXXXXXXXp文件

initial
  $dumpvars;
//没有指定变量范围,把设计中全部信号都转储

initial
  $dumpvars(1,top);
//转储模块实例top中的信号
//数1表示层次的等级,只转储top下第一层信号。
//即转储top模块中的变量,而不转储在top中调用
//模块中的变量

initial
  $dumpvars (2,XXXXXX);
//转储XXXXXX模块下两层的信号

initial
  $dumpvars (0,XXXXXX);
//数0表示转储XXXXXX模块快下面各个层的所有信号

//启动和停止转储过程
initial
begin
  $dumpon;
  //启动转储过程
  #100000 $dumpoff;
  //过了100000个仿真时间单位后,停止转储过程
end

//生成一个检查点,转储所有VCD变量的先行值
initial
  $dumpall;


为什么在多个模块调试的情况下$monitor需要配合$moniteron和$monitoroff来工作?
$monitoron和$monitoroff任务的作用是通过打开和关闭监控标志来控制监控任务$monitor的启动和停止,这样使得程序员可以很容易的控制$monitor何时发生。$monitoron则用于打开监控标志,启动监控任务$monitor。通常在通过调用$monitoron来启动$monitor时不管$monitor参数列表中的值是否发生改变,总是立刻输出显示当时时刻参数列表中的值,这用于在监控的初始时刻设定初始比较值。在默认情况下,控制标志在仿真的起始时刻就已经打开了。在多模式调试的情况下,许多模块中都调用了$monitor,因为任何时刻只能用一个$monitor起作用,因此需配合$monitoron与$monitoroff使用,把需要监视的模块用$monitor打开,再监视完毕后及时用$monitoroff关闭,以便把$monitor让给其他模块使用。

请用$random配合求模运算编写:
用于测试的跳变沿抖动为周期1/10的时钟波形。
随机出现的脉宽随机的窄脉宽。
module random_pulse(dout)
  output [9:0] dout;
  reg [9:0] dout;
  integer delay;
  initial
  begin
    #10 dout = 0;
      for (k = 0; k < 100; k = k + 1)
        begin
          delay = {$random} % 10;
          #delay dout = 1;
          #delay dout = 0;
        end
  end
endmodule

Verilog的编译预处理与C语言的编译预处理有什么不同?
Verilog的编译处理,在编译处理命令之前以“`”开头。
C语言的编译处理,在编译处理命令之前以“#”开头。

请仔细阐释`timescale编译预处理的作用?
`timescale命令用来说明跟在该命令后的模块的时间单位和时间精度。使用`timescale命令可以在同一个设计里包含采用了不同的时间单位的模块。

不同`timescale定义的多模块仿真测试时需要注意什么?
如果在同一个设计里,多个模块中用到的时间单位和时间精度单位不同,需要用到以下的时间结构:
用`timescale命令来声明本模块中所用到的时间单位和时间精度;
用系统任务$printtimescale来输出显示一个模块的时间单位和时间精度;
用系统任务$time和$realtime及%t格式声明来输出显示EDA工具记录的时间信息。

为什么说系统任务$readmen可以用来产生用于算法验证的极其复杂的测试也能够数据流?
在Verilog HDL程序中有两个系统任务$redmemb和$readmemh,并用来从文件中读取数据到存储器中,这两个系统任务可以在仿真的任何时刻被执行使用。复杂的数据可以用C语言产生,存在文件中,用$readmem取出存入存储器,在按节拍输出,这在验证算法逻辑电路时特别有用。

为什么熟练的使用条件编译命令可以使源代码有更大的灵活性,可以使用于不同的实现对象,如不同工艺的ASIC或速度规模不同的FPGA或CPLD,从而为软核的商品化创造条件?
合理的使用条件编译和条件执行预处理可以使测试程序适应不同的编译环境,也可以把不同的测试过程编写到一个统一的测试程序中去,可以简化测试的过程,对于复杂设计的验证模块的编写很有实用价值。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
534711
[例]:
例5.1
case (select[1:2])
  2'b00:  result = 0;
  2'b01:  result = flaga;
  2'b0x,
  2'b0z:  result = flaga? 'bx : 0;
  2'b10:  result = flagb;
  2'bx0,
  2'bz0:  result = flagb? 'bx : 0;
  default: result = 'bx;
endcase

例5.2
case(sig)
  1'bz:  $display("signal is floating");
  1'bx:  $display("signal is unknown");
  default:  $display("signal is %b",sig);
endcase

例5.3
reg [7:0] ir;
casez(ir)
  8'b1???????:  instruction1(ir);
  8'b01??????:  instruction2(ir);
  8'b00010???:  instruction3(ir);
  8'b000001??:  instruction4(ir);
endcase

例5.4
reg [7:0] r,mask;
mask = 8'bx0x0x0x0;
casex(r'mask)
  8'b001100xx:  stat1;
  8'b1100xx00:  stat2;
  8'b00xx0011:  stat3;
  8'bxx001100:  stat4;
endcase

通过以上三个例子比较case , casex , casez的区别。casez将高阻值z的情况视为不必关心的情况。casex将高阻值z和不定值x视为不必关心的情况。所谓不必关心的情况,即在表达式进行比较时,不将该位的状态考虑在内。


例5.5
//第一类条件语句,没有else。
//其后的语句执行或不执行
if (!lock) buffer = data;
if (enable) out = in;

//第二类条件语句,有一个else。
//根据表达式的值,决定执行ture或false。
if (number_queued < MAX_Q_DEPTH)
  begin
    data_queue = data;
    number_queued = number_queued + 1;
  end
else
  $display("Queue Full. Try again.");

//第三类条件语句,嵌套的if_else_if
//根据不同的算术逻辑单元控制信号,只有一条执行。
if (alu_control == 0)
  y = x + z ;
else if (alu_control == 1)
  y = x - z ;
else if (alu_control == 2)
  y = x * z ;
else
  $display("Invalid ALU control signal.");

通过上面的例子熟悉Verilog三种条件语句。

例5.6
使用case语句实现四选一多路选择器。
module mux4_to_1 (out,i0,i1,i2,i3,s1,s0);

  //声明输入输出端口
  output out;
  input i0,i1,i2,i3,s1,s2;

  //定义寄存器变量用于always块。
  reg out;

  always @(s1 or s0 or i0 or i1 or i2 or i3)
  begin
    case ({s1,s0})
      2'b00:  out = i0;
      2'b01:  out = i1;
      2'b10:  out = i2;
      2'b11:  out = i3;
    endcase
  end
endmodule

通过上面的例子熟悉多路分支case的使用。

例5.8
parameter size = 8,longsize = 16;
reg [size:1] opa , opb;
reg [longsize:1] result;

begin:mult
  integer bindex;;
  result = 0;
  for (bindex = 1; bindex <= size; bindex = bindex + 1)
    if(opb[bindex])
      result = result + (opa << (bindex - 1));
end

//for语句循环变量增值表达式可以不必是一般的常规加减法,如:
begin: countls
  reg [7:0] tempreg;
  count = 0;
  for(tempreg = rega; tempreg; tempreg = tempreg >> 1)
    if (tempreg[0])
      count = count + 1;
end

通过以上例子熟悉循环语句的用法。

例5.9
顺序块:
reg x,y;
reg [1:0] z,w;
initial
begin
  x = 1'b0;
  #5 y = 1'b1;
  #10 z = {x,y};
  #20 w = {y,x};
end
例5.10
并行块:
reg x,y;
reg [1:0] z,w;

initial
  fork
    x = 1'b0;
    #5 y = 1'b1;
    #10 z = {x,y};
    #20 w = {y,x};
  join

通过以上两个例子区别顺序块和并行块的区别。

例5.11
嵌套块:
initial
begin
  x = 1'b0;
  fork
    #5 y = 1'b1;
    #10 z = {x,y};
  join
  #20 w = {y,x};
end

顺序块,并行块可以互相随意嵌套。

例5.12
命名块:
module top;
initial
begin:  block1
  integer i;
  ...
  ...
end

initial
fork:  block2
  reg i;
  ...
  ...
join

例5.13
命名块的禁用。
//在(矢量)标志寄存器的各个位中从低有效位开始找寻第一个值为1的位。
reg [15:0] flag;
integer i;

initial
begin
  flag = 16'b0010_0000_0000_0000;
  i = 0;
  begin:  block1
    while (i < 16)
    begin
      if (flag[i])
      begin
        $display("Encountered a TRUE bit at element number %d",i);
        disable block1;
      end
      i = i + 1;
    end
  end
end

通过以上例子熟悉利用$disable禁用已经命名的块。

例5.14  循环生成语句
对两个N位总线变量进行按位异或。

//本模块生成两条N位总线变量的按位异或
module bitwise_xor (out , i0 , i1) ;
//参数声明语句,参数可以重新定义
parameter N = 32 ;
//默认的总线位宽为32位。

//端口声明语句
output [N-1:0] out ;
input [N-1:0] i0 , i1 ;

//声明一个临时循环变量
genvar j ;

//用一个单循环生成按位异或的异或门xor
generate
  for (j = 0; j < N; j = j + 1)
    begin : xor_loop
      xor g1 (out[j] , i0[j] , i1[j]);
    end
endgenerate
endmodule


//另一种编写方式,用always块代替异或门xor。
reg [N-1:0] out;
generate
  for (j = 0 ; j < N ; j = j + 1)
    begin : bit
      always @ (i0[j] or i1[j])
        out[j] = i0[j] ^ i0[j] ;
    end
endgenerate

用上述例子学习循环生成语句的写法。

例5.16  使用条件生成语句实现参数化乘法器。
//本模块实现一个参数化乘法器
module multiplier (product , a0 , a1) ;
//参数声明,该参数可以被重新定义。
parameter a0_width = 8 ;
parameter a1_width = 8 ;

//本地参数声明。本地参数不能用参数重新定义修改。
localparam product_width = a0_width + a1_width ;

//端口声明语句
output [product_width - 1:0] product ;
input [a0_width - 1:0] a0 ;
input [a1_width - 1:0] a1 ;

//有条件的调用不同类型的乘法器
//根据参数a0_width和a1_width的值,在调用时引用相对应的乘法器实例。
generate
  if (a0_width < 8)||(a1_width < 8)
    cal_multiplier  # (a0_width , a1_width) m0 (product , a0 , a1) ;
  else
    tree_multiplier # (a0_width , a1_width) m0 (product , a0 , a1) ;
endgenerate
endmodule

用上面的例子熟悉条件生成语句。

例5.17  case生成语句
//本模块生成N位的加法器
module adder (co , sum , a0 , a1 , ci);
//参数声明
parameter N = 4;
//默认总线位宽为4。

//端口声明
output [N - 1:0] sum ;
output co ;
input [N - 1:0] a0 , a1 ;
input ci ;

//根据总线的位宽,调用相应的加法器。
generate
  case(N)
    1 : adder_1bit  adder1 (co , sum , a0 , a1 , ci) ;
    //1位的加法器
    2 : adder_2bit  adder2 (co , sum , a0 , a1 , ci) ;
    //2位的加法器
    default : adder_cla #(N) adder3(co , sum , a0 , a1 , ci) ;
  endcase
endgenerate

endmodule

用上面的例子熟悉case生成语句。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
534712
:[例]
例6.6  or事件控制(敏感列表)。
//有异步复位的电平敏感锁存器
always @ (reset or clock or d)
begin
  if (reset)
    q = 1'b0 ;
  else if(clock)
    q = d ;
end

例6.7  逗号事件控制(敏感列表)
//有异步复位的电平敏感锁存器
always @ (reset , clock , d)
begin
  if (reset)
    q = 1'b0 ;
  else if(clock)
    q = d ;
end

上面两个能看出,or和逗号一个意思,可替换。

例6.8  @*操作符的使用
//用or操作符的组合逻辑块
//编写敏感列表很繁琐,并且很容易漏掉几个
always @(a or b or c or d or e or f or g or h or p or m)
  begin
    out1 = a? (b + c) : (d + e) ;
    out2 = f? (g + h) : (p + m) ;
  end

//用@*来代替所有输入变量
always @(*)
begin
  out1 = a? (b + c) : (d + e) ;
  out2 = f? (g + h) : (p + m) ;
end

例6.9 描述红绿黄交通灯行为的Verilog模块,学习其中使用的任务。
module traffic_lights;
  reg clock , red , amber , green ;
  parameter on = 1 , off = 0 , red_tics = 350 , amber_tics = 30 , green_tics = 200 ;
  
  //交通灯初始化
  initial red = off ;
  initial amber = off ;
  initial green = off ;

  //交通灯控制时序
  always
    begin
      red = on ;
      light (red , red_tics) ;
      green = on ;
      light (green , green_tics) ;
      amber = on ;
      light (amber , amber_tics) ;
    end

  //定义交通灯开启时间的任务
  task light;
    output color ;
    input [31:0] tics ;
    begin
      repeat(tics)
        @(posedge clock) ;
        //等待tics个时钟的上升沿
      color = off;
    end
  endtask

  //产生时钟脉冲的always块
  always
    begin
      #100 clock = 0 ;
      #100 clock = 1 ;
    end
endmodule

例6.10  阶乘函数的定义和调用。
module tryfact ;
  //函数的定义-------------
  function [31:0] factorial;
    input [3:0] operand ;
    reg [3:0] index ;
    begin
      factorial = 1;
      for (index = 2; index <= operand; index = index + 1)
      factorial = index * factorial ;
    end
  endfunction
  
  //函数的测试---------------
  reg [31:0] result ;
  reg [3:0] n ;
  initial
  begin
    result = 1;
    for(n = 2; n <= 9; n = n + 1)
    begin
      $display ("[s:9]artial result n = %d result = %d",n,result);
      result = n * factorial(n)/((n * 2) + 1) ;
    end
    $display("Finalresult = %d",result);
  end
endmodule

利用上述实例,学习函数的使用方式。

例6.19
module printval;
  reg [11:0] rl ;
  initial
    begin
      rl = 10 ;
      $display ("[s:9]rinting with maximum size = %d = %h",rl,rl) ;
      $display ("[s:9]rinting with minimum size = %0d = %0h",rl,rl) ;
    end
endmodule

输出结果为:
Printing with maximum size = 10 = 00a
Printing with maximum size = 10 = a

上述例子熟悉任务$display的用法。

例6.20  文件描述符
//多通道文件描述符
integer handle1,handle2,handle3 ;
//整型数为32位
initial
  begin
    handle1 = $fopen("file1.out") ;  //handle1 = 32’h0000_0002
  handle2 = $fopen("file2.out") ;  //handle2 = 32’h0000_0004
    handle3 = $fopen("file3.out") ;  //handle3 = 32’h0000_0008
  end

//写文件
//把输出写到文件描述符值为1的所有文件中。
integer desc1,desc2,desc3 ;
initial
  begin
    desc1 = handle1 | 1 ;  //desc1 = 32'h0000_0003
    $fdisplay (desc1,"Display 1") ;  //写文件到file1.out

    desc2 = handle2 | handle1 ;  //desc2 = 32'h0000_0006
    $fdisplay (desc2,"Display 2") ;  //写文件到file2.out

    desc3 = handle3 ;    //desc3 = 32'h0000_0008
    $fdisplay (desc3,"Display 3") ;  //写文件到file3.out
  end

//关闭文件
$fclose(handle1) ;
$fclose(handle2) ;
$fclose(handle3) ;

用以上例子熟悉文件的输出。

例6.23
值变转储文件。
initial
  $dumpfile ("XXXXXXXXXp");
  //仿真信息转储到XXXXXXXXXp文件

initial
  $dumpvars;
//没有指定变量范围,把设计中全部信号都转储

initial
  $dumpvars(1,top);
//转储模块实例top中的信号
//数1表示层次的等级,只转储top下第一层信号。
//即转储top模块中的变量,而不转储在top中调用
//模块中的变量

initial
  $dumpvars (2,XXXXXX);
//转储XXXXXX模块下两层的信号

initial
  $dumpvars (0,XXXXXX);
//数0表示转储XXXXXX模块快下面各个层的所有信号

//启动和停止转储过程
initial
begin
  $dumpon;
  //启动转储过程
  #100000 $dumpoff;
  //过了100000个仿真时间单位后,停止转储过程
end

//生成一个检查点,转储所有VCD变量的先行值
initial
  $dumpall;

通过上面例子熟悉值变转储文件任务,$dumpfile , $dumpvars , $dumpon , $dumpoff , $dumpall
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
534713
:[例]
例7.1
`timescale 10 ns/1 ns
module test ;
  reg set ;
  parameter p = 1.6 ;
  initial
    begin
      $monitor ($time , , "set = " , set) ;
      #p set = 0 ;
      #p set = 1 ;
    end
endmodule


输出结果:
0 set = x
2 set = 0
3 set = 1

用上述例子熟悉时间度量函数$time(整型)$realtime(实型)。

例7.3  初始化存储器
module test ;
  reg [7:0] memory [7:0] ;
  //8个8位的存储单元
  integer i ;

  initial
    begin
      $readmemb ("init.dat",memory) ;
      //读取存储器init.dat到存储器给定地址
      for (i = 0; i < 8; i = i + 1)
        $display ("Memory [%d] = %b",i,memory[i]) ;
    end
endmodule

init.dat文件内容:
@002
11111111  01010101
00000000  10101010

@006
1111zzzz  00001111

输出结果:
Memory [0] = xxxxxxxx
Memory [1] = xxxxxxxx
Memory [2] = 11111111
Memory [3] = 01010101
Memory [4] = 00000000
Memory [5] = 10101010
Memory [6] = 1111zzzz
Memory [7] = 00001111

通过上面的例子,熟悉任务$readmemb(二进制),$readmemh(十六进制)。

例7.4
`timescale 1 ns/1 ns
module random_pules(dout) ;
  output [9:0] dout ;
  reg [9:0] dout ;

  integer delay1 , delay2 , k ;

  initial
  begin
    #10 dout = 0 ;
    for (k = 0; k < 100; k = k + 1)
    begin
      delay1 = 20 * ({$random} % 6) ;
      delay2 = 20 * ({$random} % 3) ;
      #delay1 dout = 1 << ({$random} % 10) ;
      #delay2 dout = 0 ;
    end
  end
endmodule

用上述例子熟悉随机数任务{$random}((-b+1)到(b-1)中随机数),$random((b-1)到0中随机数)。

例7.9  预处理命令
//文件的包含预处理
(1)文件aaa.v
module aaa(a,b,out) ;
  input a , b ;
  output out ;
  wire out ;
    assign out = a ^ b ;
endmodule

(2)文件bbb.v
`include "aaa.v"
module bbb(c , d , e ,out) ;
  input c , d , e ;
  output out ;
  wire out_a ;
  wire out ;
  aaa aaa(.a(c),.b(d),.out(out_a)) ;
  assign out = e & out_a ;
endmodule

用上述例子熟悉预处理命令:`include , `define , `timescale , `ifdef , `else , `endif。

:总复习练习:
设计电路

module AOI (A,B,C,D,F) ;
  input A,B,C,D ;
  output F ;
  assign F = ((A&b)&(C&D)) ;
endmodule

设连接线为W1,W2,W3,W4,W5,连入已知全加器模块FullAdder。
//已知:
module FullAdder (A,B,Cin,Sum,Cout) ;
  input A,B,Cin ;
  output Sum,Cout ;
endmodule

//接口电路:
module Top ;
  FullAdderFA (.sum(W1),.Cout(W2),.Cin(W3),.A(W4),.B(W5)) ;
endmodule

某测试模块语句排序。
答案:
module TestFixture ;
  reg A,B,SSEL ;
  wire F ;
  MUX2M(SEL,A,B,F) ;
  initial
  begin
    SEL = 0 ;
    A = 0 ;
    B = 0 ;
    #10 A = 1 ;
    #10 SEL = 1 ;
    #10 B = 1 ;
  end
  
  initial
    $monitor (SEL,A,B,,F) ;//两个逗号中间空的,表示空格一个。
endmodule

指出下面信号的最高位和最低位。
reg [1:0] SEL ;
input [0:2] IP ;
wire [16:23] A ;

答案:
最高位:SEL[1] , IP[0] , A[16] ;
最低位:SEL[0] , IP[2] , A[23] ;

P,Q,R都是4bit的输入矢量,下面哪一种是正确的表达形式?
XXXXput P[3:0] , Q , R ;
XXXXput P , Q , R[3:0] ;
XXXXput P[3:0] , Q[3:0] , R[3:0] ;
XXXXput [3:0] P , [3:0] Q , [3:0] R ;
XXXXput [3:0] P,Q,R;

答案:5.


请将正确答案填入方括号。
1.(0:2)
2.(P:0)
3.(Op1:Op2)
4.(7:7)
5.(2:0)
6.(7:0)

reg [7:0] A ;
reg [2:0] Sum , Op1 , Op2 ;
reg P , OneBit ;

initial
begin
  Sum = Op1 + Op2 ;
  P = 1 ;
  A[] = Sum ;
end

答案:5.

选择:
XXXXg [7:0] A ;
  A = 1'hFF ;
A.8'b0000_0011
B.8'h03
C.8'b1111_1111
D.8'b11111111
答:A和B.

XXXXg [7:0] B ;
  B = 8'bZ0 ;
A.8'0000_00Z0
B.8'bZZZZ_0000
C.8'b0000_ZZZ0
D.8'bZZZZ_ZZZ0
答:D.

指出变量类型:
XXXXsign A = B ;
XXXXways #1
    Count = C + 1 ;

答案:A(wire) , B(wire/reg) , Count(reg) , C(wire/reg)
这第九题我特么的也不会。。。。。。
设ADDRESS为5’b0X000下列程序结束后A和B值为多少?
A = 0 ;
B = 0 ;
casex(ADDRESS)
  5'b00???: A = 1 ;
  5'b01???: B = 1 ;
  5'b10?00,
  5'b11?00: begin
              A = 1 ;
              B = 1 ;
            end
endcase

答案:A = 1 , B = 0。

假设事件A分别在10,20,30发生。B一直是X。问50时,Count的值为多少?
reg [7:0] Count ;
initial
  Count = 0 ;
always
begin
  @(A) Count = Count + 1 ;
  @(B) Count = Count + 1 ;

end

答案:Count = 1。是个顺序块,两条必须都执行完才always重复执行。因为B一直是X,所以执行到@(B) Count = Count + 1 ;就不往下进行了。

结束后I , J , A , B值为多少?
reg [2:0] A ;
reg [3:0] B ;
integer I , J ;
initial
begin
  I = 0 ;
  A = 0 ;
  I = I - 1 ;
  J = I ;
  A = A - 1 ;
  B = A ;
  J = J + 1 ;
  B = B + 1 ;
end

答案:
I = -1
J = 0
A = 7
B = 8

假设V的值变化成-1时,执行always块后,Count值为多少?
reg [7:0] V ;
reg [2:0] Count ;

always @(V)
begin
  Count = 0 ;
  while(~V[Count])
  Count = Count + 1 ;
end

答案:Count = 0 ;8位数据-1就是1111_1111,按位取反就是0000_0000,结果while就没有执行。还是初始化时候的Count = 0。

V的值是多少?
reg [3:0] A ;
reg V , W ;
integer K ;
...
A = 4'b1010 ;
for(K = 2; K >= 0; K = K - 1)
begin
  C =  V ^ A[K] ;
  W = A[K] ^ A[K + 1] ;
end

答案:第二位和第四位取反,别的不变。因为按位异或运算,与0不变,与1取反。A = 4'b1010。

给出片段代码,问它可能是什么电路的部分代码?
always @(posedge Clock)
  if (A)
    C = B ;

1.不能综合。
2.一个上升沿触发器和一个多路器。
3.一个输入时A,B,Clock的三输入与门。
4.一个透明锁存器。
5.一个带clock有使能引脚的上升沿触发器。

答案:2和5。

下列程序中,always状态将描述一个带异步Nreset和Nset输入端的上升沿触发器。括号内应填入什么?
always @()
  if (! Nreset)
    Q <= 0 ;
  else if (! Nset)
    Q <= 1 ;
  else
    Q <= D ;

XXXXgedge Nset or posedge Clock
2.posedge Clock
XXXXgedge Nreset or posedge Clock
XXXXgedge Nreset or negedge Nset or posedge Clock
XXXXgedge Nreset or negedge Nset

答案:4。上升沿触发器说的是时钟Clock。由代码知Nreset和Nset低电平有效。

综合后结果。
1.
always @(posedge Clock)
begin
  A <= B ;
  if (C)
    A <= 1'b0 ;
end

答案:带同步复位端的触发器。

2.
always @(A or B)
  case (A)
    1'b0: F = B ;
    1'b1: G = B ;
  endcase
答案:不能综合或与预想不一致。

3.
always @(posedge A or posedge B)
  if (A)
    C <= 1'b0 ;
  else
    C <= D ;
答案:带异步复位端的触发器。

4.
always @(posedge Clk or negedge Rst)
  if (Rst)
    A <= 1'b0 ;
  else
    A <= B ;
答案:不能综合或与预想不一致。

会产生几个触发器?
always @(posedge Clk)
begin: Blk
  reg B , C ;
  C = B ;
  D <= C ;
  B = A ;
end

答案:两个寄存器,B和C。

程序语句排序。
reg FF1 , FF2 , FF3;
always @(posedge Clock)
begin
  FF1 <= Input ;
  FF2 <= FF1 ;
  FF3 <= FF2 ;
  Output <= FF3 ;
end

根据SEL与OP的关系,补全程序:
关系:
SEL:OP
000:1
001:3
010:1
011:3
100:0
101:3
110:0
111:3

答案:
casex(SEL)
3'bXX1:  OP = 3 ;
3'b0X0:  OP = 1 ;
3'b1X0:  OP = 0 ;
endcase

选出正确的表达式:
3.! 4'b1011 || ! 4'b0000 = 1'b1
5.1'b0 || 1'b1 = 1b'1
9.4'b0001 || 4'b0000 = 1'b1

填入display的正确值。
integer I ;
reg [3:0] A ;
reg [7:0] B ;
initial
begin
  I = -1 ;
  A = I ;
  B = A ;
  $display ("%b",B) ;  //(00001111)
  A = A / 2 ;
  $display ("%b",A) ;  //(0111)
  B = A + 14 ;
  $display ("%d",B) ;  //(21)
  A = A + 14 ;
  $display ("%d",A) ;  //(5)
  A = -2 ;
  I = A / 2 ;
  $display ("%d",I) ;  //(7)
end

{1,0}和下面那个值相等?
答案:5. 64’H0000_0001_0000_0000
不写位宽默认为32位位宽。

补全代码:
//file defs.v
module defs ;
  parameter Reset = 8'b10100101 ;
endmodule

//file M.v
module M;
  `include "defs.v"
  if (OP == <XXXXXXXset>)
    Bus = 0 ;
endmodule

调用Pipe模块时,想把Depth的值更改为8,怎么做。
module Pipe(IP , OP)
  parameter Option = 1 ;
  parameter Depth = 1 ;
  ...
endmodule

Pipe #(1,8) P1(IP1 , OP1) ;
解答:#(1,8)中1对应参数Option,8对应参数Depth。

若想将P1中Depth值变为16,怎么做?
module Pipe (IP , OP) ;
  parameter Option = 1 ;
  parameter Depth = 1 ;
  ...
endmodule

module
  Pipe P1(IP1 , OP1) ;
  defparam XXXXXpth = 16 ;
endmodule

我特么的又不会了。。。。。。
下面代码,每次赋值都赋的什么值。
reg [7:0] V
initial
begin
  V = 8'b0 ;  //8'b0000_0000
  V = 8'b1 ;  //8'b0000_0001
  V = 8'bX ;  //8'bXXXX_XXXX
  V = 8'BZX ;  //8'bZZZZ_ZZZX
  V = 8'BXXZZ ;  //8'bXXXX_XXZZ
  V = 8'b1x ;  //8'b0000_001X
end
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
534716
实验:
实验一:
//compare.v
module compare (equal , a , b) ;
  input a , b ;
  output equal ;
  assign equal = (a == b) ? 1 : 0 ;
endmodule

//t.v
`timescale 1 ns/1 ns
`include "./compare.v"

module t ;
  reg a , b ;
  wire equal ;
  initial
  begin
    a = 0 ;
    b = 0 ;
    #100 a = 0 ; b = 1 ;
    #100 a = 1 ; b = 1 ;
    #100 a = 1 ; b = 0 ;
    #100 a = 0 ; b = 0 ;
    #100 $stop ;
  end
  
  compare m(.equal(equal),.a(a),.b(b)) ;
endmodule



实验二:
//half_clk.v
module half_clk (reset , clk_in , clk_out) ;
  input clk_in , reset ;
  output clk_out ;
  reg clk_out ;
  
  always @ (posedge clk_in)
  begin
    if (! reset)
      clk_out = 0 ;
    else
      clk_out = ~clk_out ;
  end
  
endmodule

//t.v
`timescale 1 ns/100 ps
`define clk_cycle 50

module top ;
  reg clk , reset ;
  wire clk_out ;
  
  always #`clk_cycle clk = ~clk ;
  
  initial
  begin
    clk = 0 ;
    reset = 1 ;
    #10 reset = 0 ;
    #110 reset = 1 ;
    #100000 $stop ;
  end
  
  half_clk m0(.reset(reset),.clk_in(clk),.clk_out(clk_out)) ;
endmodule



实验三:
//fdivision.v
module fdivision (RESET , F10M , F500K) ;
  input F10M , RESET ;
  output F500K ;
  reg F500K ;
  reg [7:0] j ;
  always @ (posedge F10M)
    if (! RESET)
      begin
        F500K <= 0 ;
        j <= 0 ;
      end
    else
      begin
        if (j == 19)
          begin
            j <= 0 ;
            F500K <= ~F500K ;
          end
        else
          j <= j + 1 ;
      end
endmodule

//t.v
`timescale 1ns/100ps
`define clk_cycle 50
`include "fdivision.v"

module t ;
  reg F10M , RESET ;
  wire F500K_clk ;
  
  always #`clk_cycle F10M = ~ F10M ;
  
  initial
  begin
    RESET = 1 ;
    F10M = 0 ;
    #100 RESET = 0 ;
    #100 RESET = 1 ;
    #10000 $stop ;
  end
  
  fdivision fdivision(.RESET(RESET),.F10M(F10M),.F500K(F500K_clk)) ;
  
endmodule
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
534717
呃。。。发完了,发现序号怎么都没有了。。。
还有仿真波形图怎么粘上???
算了,先这样吧…………
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
534735
回 10楼(能材爱好者) 的帖子
[s:307]对化学无爱~~~
现在就是专心研究微电子方向,加上个人爱好研究医学~~~
我这里有这些年来的笔记,都是电子档的,习惯了抱着电脑看书记笔记,都快不会写字了,嘿嘿~
+1
科创币
delete
2013-06-11
我最近打算玩激光,还要设计电路,我玩平时爪机习惯了手写输入
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
534775
回 12楼(jrcsh) 的帖子
确切的说是读书笔记,在我看完夏宇闻的Verilog教材后,随手记得笔记。。。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
534779
回 14楼(usafn6132) 的帖子
[s:275]话说这个比篇幅什么的完全没什么意义……笔记这种东西记过之后自己都基本不会再看,主要是当时为了方便学习记忆做的。。。

话说你们都那么喜欢玩炸弹么……之前据说这个论坛不是还炸残疾了一个,多危险啊……
[s:274][s:274]还是大爱弱电~~~

下次发笔记的时候直接用附件上传好了,想看的自己下载~~~
-2
科创币
kc地毯清洁员
2013-06-11
特斯拉多危险啊,莱特兄弟多危险啊,高考多危险啊
+2
科创币
daxus
2013-06-12
正常表达自己的观点,加回来
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
世纪伯乐作者
11年7个月前 IP:未同步
535054
kc地毯清洁员
有原文件,我用附件重发好了。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
世纪伯乐
笔友
文章
17
回复
138
学术分
0
2013/06/11注册,6年11个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}