alicemare / ideas

用Issue来记录一些简单的笔记?
0 stars 0 forks source link

VerilogHDL notes in COD #7

Open alicemare opened 5 years ago

alicemare commented 5 years ago

计算机的学习是这样的,混得了一时混不过一世 逃避掉的,终究是要还回去的 上学期学数电的时候就没有认真,花时间,投入兴趣的去学习,结果是被动的,但是幸好至少都跟着做了,虽然迷迷糊糊的,但是最后我也是把每一个实验都完成了的,所以,还是有基础的 组成原理,体系结构都是要用到verilog的,想贯通计算机的软硬件也是逃不过对其深入的理解的 所以,拿出当时学化学的那股拼劲吧,让硬件基础成为你以后拿出去的资本

鸡汤到此为止


一更

嘛,写的时候动动脑袋瓜

如果入门verilog的时候觉得无从下手,其实应该回归原点思考一下,我在干啥?? verilog是一门硬件语言,是用来描述你想要的硬件电路(这里大多是RTL级 所以在打开xilinx vivado之前,最应该做到的几点是

  1. 对你要描述的硬件在心中胸有成竹;
  2. 牢记可综合Verilog HDL与电路结构一一对应的关系;
  3. 确认电路指标是什么:性能?面积?
  4. 硬件思维方式,代码不再是一行行的代码而是一块一块的硬件模块;
alicemare commented 5 years ago

以下转自 只是个大略的复习

1.变量类型

Net Type(连线型),从名字上理解就是“导线”,导线的这头和导线的另一头始终是直接连通的,这头是什么值,那头就是什么值,所以输出随着输入随时变化的。连线型中 wire 最常见。

Register Type(寄存器型),寄存器就不像普通导线了,它可以把值给存住,你只要给它赋一次值,它都会存住那个值,直到你给它赋一个新的值它才会改变。寄存器型中 reg 最常见。

最常用到的是 wire 和 reg 这两种类型,其他的对初学者来说一般很少用到,可以暂时跳过,以后慢慢学下去自然会理解。

注意:wire型变量如果没有赋予初始值,默认初始值为高阻态“Z”。 reg 型变量如果没有赋予初始值,默认初始值为不定态“X”。

2.赋值语句类型

在理解这两种基本的数据类型之后,我们来看看verilog语言中的赋值语句。verilog语言中的赋值语句有两种,一种是持续赋值语句(assign语句),另一种是过程赋值语句(always语句)。

持续赋值语句(assign语句)主要用于对wire型变量的赋值,因为wire(线型)的值不能存住,需要一直给值,所以需要用持续赋值。

可以如此理解assign语句,就像用一个assign out = a&b,综合之后即为out作为a和b直接”与“的结果

例如:assign c = a + b; 只要a和b有任意变化,都可以立即反映到c上,也就是说c的值是根据a,b的值随时变化的。

过程赋值语句(always语句)主要用于reg 型变量的赋值 ,因为always语句被执行是需要满足触发条件的,所以always过程块里面的内容不是每时每刻都被执行,因此需要将被赋值的对象定义成寄存器类型,以便这个值能被保持住。

过程赋值又分为 阻塞赋值 “=” 和 非阻塞赋值 “<=” 两种。这里的非阻塞赋值符号 “<=” 与 “小于等于” 符号相同,他们在不同的语境下表示不同含义,要注意区分,例如在“if-else”等判断语句中,一般都表示为“小于等于”。

接下来对这两种赋值作具体讲解...

① 阻塞赋值 “=“ 。 阻塞赋值和我们平时理解的赋值差不多,不用太多解释,就是按照语句的顺序,一句句往下顺序执行。一个赋值语句执行完,然后执行下一个赋值语句。

② 非阻塞赋值 “<=” 。非阻塞赋值就比较特别了,在同一个always过程块中,非阻塞赋值语句都是同时并发执行的,并且在过程块结束时才执行赋值操作。也就是说,在同一个always过程块中,非阻塞赋值语句被执行没有先后顺序,在过程快结束时,大家一起被赋值。

module test (clk, a1, a2, b1, b2, c1, c2); // test为module名称,括号内的是端口列表,包含所有输入输出的变量名称

input clk, a1, a2;           // 定义输入变量,这里没有定义位宽,默认为1位宽度

 output b1, b2, c1, c2;    // 定义输出变量,这里没有定义位宽,默认为1位宽度

 reg b1 = 0 , b2 = 0, c1 = 0 , c2 = 0;   // 注意!因为这些变量将会在always过程块中被赋值,所以必须定义成 reg 型    

// 注意!这里省略了对输入信号clk, a1, a2 的类型定义,它们默认为1位的wire 型(因为输入信号是随时要变化,所以必须用wire型)              

always @ (posedge clk)   // always 用 clk 上升沿触发

    begin

        b1 = a1;       // 这里采用的是阻塞赋值

        c1 = b1;

    end

always @ (posedge clk)  // always 用 clk 上升沿触发

    begin

        b2 <= a2;    // 这里采用的是非阻塞赋值

        c2 <= b2;

    end   

endmodule     // endmodule 别忘了,与 module 成对使用
alicemare commented 5 years ago

always的用法

CS150资料 改下URL后缀还有FSM等... =<=赋值 always有两种用法

always @ (*) 用于组合逻辑 只有=赋值 而always @ (posedge clk) 只能用于时许逻辑 只有<=赋值

always@(posedge Clock) (“always at the positive edge of the clock”) or always@(negedge Clock) (“always at the negative edge of the clock”) blocks are used to describe Sequential Logic, or Registers. Only <= (non-blocking) assignments should be used in an always@(posedge Clock) block. Never use = (blocking) assignments in always@(posedge Clock) blocks. Only use always@(posedge Clock) blocks when you want to infer an element(s) that changes its value at the positive or negative edge of the clock.

always@( ) blocks are used to describe Combinational Logic, or Logic Gates. Only = (blocking) assignments should be used in an always@( ) block. Never use <= (non-blocking) assignments in always@( ) blocks. Only use always@( ) block when you want to infer an element(s) that changes its value as soon as one or more of its inputs change.

alicemare commented 5 years ago

关于always的pitfalls

关于verilog一直都不缺少一些神奇的bug 比如CS150的主页就用subtle来描述这些头疼的问题,所以写代码时候一定要注意照顾这几点

  1. always @ (*)中用 <=,always @(posedge clk)中用=
  2. 敏感列表未写全
  3. 可能产生latch

第一个问题会直接让代码逻辑错误,比如shift regs,必须为<=,如果用成=,则所有位都是一个值

always @ ( posedge Clock ) begin
B = A ;
C = B ;
D = C ;
end

综合结果为

第二个则会产生一些难以预料到的bug,所以好习惯是总用@(*)

第三个则是最长犯的,被称为latch generation

如果不能保证每次always执行的时候所有变量都被赋值,那么就会产生latch

Lastly, a very subtle point which perhaps has the potential to cause the most frustration is latch generation. If you don’t assign every element that can be assigned inside an always@( ) block every time that always@( ) block is executed, a latch (similar to a register but much harder to work with in FPGAs) will be inferred for that element. This is never what you want and is a terrible place for bugs. As this is subtle, it is somewhat hard to visualize.

wire Trigger , Pass ;
reg A , C ;

always @ ( * ) begin
A = 1 ’ b0 ;
if ( Trigger ) begin
    A = Pass ;
    C = Pass ;
end
end

A每次都会被至少赋值一次,而C可能在条件不满足时候无法赋值,所以综合会产生

正确的方法应该是确保A C都至少有一个值 所以,默认值(default value)是一种很简单常用的防止产生latch的方法

Default values are an easy way to avoid latch generation, however, will sometimes break the logic in a design. As such, other ways of ensuring that each value always gets set are going to be worth looking into. Typically, they involve proper use of the Verilog else statement, and other flow constructs. Know that setting a reg to itself is not an acceptable way to ensure that the reg always gets set. For example, C = C; enjected into the top of the always@( ) block in Program 9 will not supress latch generation. In every ‘execution’ of an always@( ) block, each value that is assigned in at least one place must be assigned to a non-trivial value during every ‘execution’ of the always@( * ) block.

alicemare commented 5 years ago

wire & reg

来自CS150Nets.pdf的直接搬运 不得不说原文太好,如果翻译不好都是一种过错乃至犯罪

1.1 wire Elements (Combinational logic)

wire elements are simple wires (or busses of arbitrary width) in Verilog designs. The following are syntax rules when using wires:

  1. wire elements are used to connect input and output ports of a module instantiation together with some other element in your design.
  2. wire elements are used as inputs and outputs within an actual module declaration.
  3. wire elements must be driven by something, and cannot store a value without being driven.
  4. wire elements cannot be used as the left-hand side of an = or <= sign in an always@ block.
  5. wire elements are the only legal type on the left-hand side of an assign statement.
  6. wire elements are a stateless way of connecting two peices in a Verilog-based design.
  7. wire elements can only be used to model combinational logic.

Program 1 shows various legal uses of the wire element.

//Program 1 Legal uses of the wire element
wire A , B , C , D , E ; // simple 1 - bit wide wires
wire [8:0] Wide ; // a 9 - bit wide wire
reg I ;

assign A = B & C ; // using a wire with an assign statement

always @ ( B or C ) begin
I = B | C ; // using wires on the right - hand side of an always@ assignment
end

mymodule mymodule_instance (. In ( D ) , . Out ( E ) ) ; // using a wire as the output of a module

1.2 reg Elements (Combinational and Sequential logic)

reg are similar to wires, but can be used to store information (‘state’) like registers. The following are syntax rules when using reg elements.

  1. reg elements can be connected to the input port of a module instantiation.
  2. reg elements cannot be connected to the output port of a module instantiation.
  3. reg elements can be used as outputs within an actual module declaration.
  4. reg elements cannot be used as inputs within an actual module declaration.
  5. reg is the only legal type on the left-hand side of an always@ block = or <= sign.
  6. reg is the only legal type on the left-hand side of an initial block = sign (used in Test Benches).
  7. reg cannot be used on the left-hand side of an assign statement.
  8. reg can be used to create registers when used in conjunction with always@(posedge Clock) blocks.
  9. reg can, therefore, be used to create both combinational and sequential logic.

Program 2 shows various legal uses of the reg element.

Program 2 Legal uses of the reg element
wire A , B ;
reg I , J , K ; // simple 1 -bit wide reg elements
reg [8:0] Wide ; // a 9 -bit wide reg element

always @ ( A or B ) begin
I = A | B ; // using a reg as the left - hand side of an always@ assignment
end

initial begin // using a reg in an initial block
J = 1 ’ b1 ;
#1
J = 1 ’ b0 ;
end

always @ ( posedge Clock ) begin
K <= I ; // using a reg to create a positive -edge - triggered register
end

1.3 When wire and reg Elements are Interchangable

wire and reg elements can be used interchangably in certain situations:

  1. Both can appear on the right-hand side of assign statements and always@ block = or <= signs.
  2. Both can be connected to the input ports of module instantiations.