@byjr-k
2016-01-06T09:01:24.000000Z
字数 10047
阅读 2334
大学学习
HDL (Hardware Description Language) is a computer language that is used to describe hardware.
Two main HDLs are used by industry:
Modules can be specified in two ways:
and(y, x1, x2);
or(y, x1, x2, x3, x4);
not(y, x);
(y
for output and x
for input(s))
module example(x1, x2, x3, f);
input x1, x2, x3;
output f;
assign f = (x1 & x2) | (~x2 & x3);
endmodule
module example(x1, x2, x3, f);
input x1, x2, x3;
output f;
reg f;
always @(x1, x2, x3)
if (x2 == 1)
f = x1;
else
f = x3;
endmodule
Concurrent statements are considered in parallel and the ordering in the code does not matter. This includes gate instantiations and continuous assignment.
assign的出现顺序不影响
Procedural statements are evaluated in the order in which they appear in the code. This statements are required to be contained inside an always block.
always中的顺序与代码保持一致
空格,制表符,空行全都无视
与C语言一样,有两种,分别是单行注释和多行注释
多行注释的效果跟C#一样,可以写在一行代码的中间
用字母或者下划线开头
后面可以是字母、数字、下划线以及美元符号($)
Why x:
Why z:
z和0,1或x相连,输出是另一个input(两个z输出z)
x和0,1或z相连,输出是x
除了AND只要有一个0就输出0,以及OR只要有一个1就输出1以外,只要input有x或z,就输出x(课件并没有指出如果有两个x、z或者x、z同时出现的output是什么)
还有一种叫不上名字的门电路,三角形,有两个输入A和S。如果S为1,则输出为A,否则为z。
size
数字的bit数,不管radix是什么
default: 32 bit
radix
基数(可以理解为进制)
default: decimal
Radix | Letter |
---|---|
decimal | d or D |
hexadecimal | h or H |
octal | o or O |
binary | b or B |
如果啥也不写,比如
wire x = 15
, 指的是32位十进制数
下划线(underscore)“_”被无视(用来增强可阅读性,如8'b0000_1010
)
如果size比数字大,则数字左边填充为0
如果数字最左边是z或x,则左边填充为z或x
同种数据可以一次性声明多个,比如
reg A, B
,reg [3:0] X, Y
integer是32位reg
1 + 1
1 - 1
-1
3 * 2
5 / 3
6 % 3
如果%运算中有负数,则先按正数计算,然后添加负号
~m // not
m & n
m | n
m ^ n // Exclusive OR
m ~^ n
m ^~ n // Both are Exclusive NOR
!m
m && n
m || n
&m
~&m
|m
~|m
^m
~^m
^~m
从左往右(反之也可)逐位计算,结果为1 bit
偶数个1或0连续异或的结果是0,奇数个0或者1连续异或的结果为1
Example:
value | & | ~& | | | ~| | ^ | ~^ |
---|---|---|---|---|---|---|
4'b0011 | 0 | 1 | 1 | 0 | 0 | 1 |
<
>
<=
>=
==
!=
===
!==
对于==(Equality Operators),只有当每一位的1或者0都相同,才能返回1。如果有x,则返回x
对于===(Identity Operators),如果每一位对应的内容相同(包括z和x),则返回1
m >> n
m << n
m <<< n
m >>> n
? :
跟C语言一样,没啥好说的
{}
Example
A = 1'b1, B = 2'b00, C = 2'b10, D = 3'b110
Y = {B, C};
Y = {B[0], D[2], 2'b11};
Y = {B, D[2:0]};
Y = {4{A}, 2{B}, C};
Operator type | Operator symbols | Precedence |
---|---|---|
Complement | ! ~ - | Highest |
Arithmetic |
|
|
Shift | << >> | |
Relational | < <= > >= | |
Equality | == != | |
Reduction | & ~& ^ ~^ | ~| | |
Logical | && || | |
Conditional | ?: | Lowest |
module fulladd(Cin, x, y, s, Cout);
input Cin, x, y;
output s, Cout;
assign {Cout, s} = x + y + Cin;
endmodule
module adder4(carryin, X, Y, S, carryout);
input carryin;
input [3:0] X, Y;
output [3:0] S;
output carryout;
wire [3:1] C;
// order
fulladd stage0(carryin, X[0], Y[0], S[0], C[1]);
// name
fulladd stage3(.Cout(carrout), .s(S[3]), .y(X[3]), .x(X[3]), .Cin(C[3]));
endmodule
module bit_count(X, Count);
parameter n = 4;
parameter logn = 2;
// ...
endmodule
module common(X, Y, C);
input [7:0] X, Y;
output [3:0] C;
wire [7:0] T;
// method 1
bit_count cbits(T, C);
defparam cbits.n = 8, cbits.logn = 3;
// method 2
bit_count #(8, 3) cbits(T, C);
感觉就是用来弄好几个连续的module,比如fulladder
// old method
module adder4(carryin, X, Y, S, carryout);
fulladd stage0(carryin, X[0], Y[0], S[0], C[1]);
fulladd stage1(carryin, X[1], Y[1], S[1], C[2]);
fulladd stage2(carryin, X[2], Y[2], S[2], C[3]);
fulladd stage3(carryin, X[3], Y[3], S[3], carryout);
endmodule
// new method
module adder4(carryin, X, Y, S, carryout);
parameter n = 4;
wire [n:0] C;
genvar i;
assign C[0] = carryin;
assign carryout = C[n];
generate
for (i=0; i<=n-1; i=i+1)
begin:addbit
fulladd stage(C[i], X[i], Y[i], S[i], C[i+1]);
end
endgenerate
endmodule
每一个instance的名称分别是
addbit[i].stage
借助大二所学知识,总能够将逻辑电路设计为借助基础逻辑门(AND, OR, NOT, XOR等)组成的电路
module fulladd(Cin, x, y, s, Cout);
input Cin, x, y;
output s, Cout;
assign {Cout, s} = x + y + Cin;
endmodule
module fulladd(Cin, x, y, s, Cout);
input Cin, x, y;
output s, Cout;
wire z1, z2, z3, z4;
and And1(z1, x, y);
add And2(z2, x, Cin);
add And3(z3, y, Cin);
or Or1(Cout, z1, z2, z3);
xor Xor1(z4, x, y);
xor Xor2(s, z4, Cin);
endmodule
下面的方法省略了原始实例的实例名称,以及涉及的wire的定义,也是可行的
module fulladd(Cin, x, y, s, Cout);
input Cin, x, y;
output s, Cout;
and(z1, x, y);
add(z2, x, Cin);
add(z3, y, Cin);
or(Cout, z1, z2, z3);
xor(z4, x, y);
xor(s, z4, Cin);
endmodule
gate_type [#(delay)] [instance_name] (input_port, ..., output_port, ...);
* gate_type 门电路的类型,所有可用的会在下面的表格中说明
* instance_name: optional
* #(delay): propagation delay in time units, optional
常见的逻辑门电路
and(f, a, b, ...)
nand(f, a, b, ...)
or(f, a, b, ...)
nor(f, a, b, ...)
xor(f, a, b, ...)
xnor(f, a, b, ...)
not(f, a)
特殊的门电路
buf(f, a) // f = a
notif0(f, a, e) // f = !e? ~a : 'bz
notif1(f, a, e) // f = e? ~a : 'bz
bufif0(f, a, e) // f = !e? a : 'bz
bufif1(f, a, e) // f = e? a : 'bz
'bz
是1'bz
的省略,1 bit的高阻态
buffer的作用大概是在电路中起到缓冲作用。如果一部分电流过大,则不至于使整个电路受到牵连
Explicit
net_type [size] net_name;
assign net_name = expression;
// Example
input x1, x2;
output f;
assign f = x1 & x2;
Implicit
net_type [size] net_name = expression;
// Example
input x1, x2;
output f = x1 & x2;
assign s = x ^ y, c = x & y;
wire s = x ^ y, c = x & y;
Procedural Statement必须出现在always或initial blocks中,或者在function或task中,而且只被内部的always或initial调用(后面这种东西压根没学过,也没见过)
D-type flip-flop
module DFF(D, Clock, Q);
input D, Clock;
output Q;
reg Q;
always @(posedge Clock) begin
Q = D;
end
endmodule
这个模块只检测clock的上升沿,不管D的状态有无改变,Q的值都只会在下一个clock上升沿进行赋值
always@后面括号中的内容为sensitivity list,可以为某个或某些信号的高低变化,或者上升沿、下降沿
括号中出现的内容只能是同种的信号,比如(s1 or s2 or s3)
,再比如(posedge c1 or negedge c2)
理论上,逗号和or可以互换,不过还是用or吧……
initial begin
Q1 = 1;
Q2 = 0;
end
// 以下代码在一个时钟周期后,Q1和Q2都等于0
always@(posedge clk) begin
Q1 = Q2;
Q2 = Q1;
end
// 以下代码在一个时钟周期后,Q1和Q2的值互换
always@(posedge clk) begin
Q1 <= Q2;
Q2 <= Q1;
end
没啥说的,完全可以理解为C语言的if用法,只不过把花括号换成begin end
case (s)
0: f = 0;
1: f = 2;
2: f = 5;
default: f = z; // optional
endcase
don't care指的是,只比较其他的1或者0
alternative中如果语句超过一行,则也要使用begin end
以上的中文语法体系已经彻底崩坏……
跟C语言没两样,除了花括号和begin end的区别
for中使用的递增数使用reg或integer类型
这俩并没用过,也没见过,更不知道forever有卵用(莫非像是单片机里面那样,出特殊情况就直接开始死循环?)
repeat (expression) statement;
forever statement;
repeat:重复expression次statement
forever:无限循环statement
// 4-to-1 multiplexer
module mux16to1(W, S16, f);
// ...
function mux4to1;
input [3:0] W;
input [1:0] S;
mux4to1 = W[S];
endfunction
// ...
endmodule
此处开始,课件变得很迷,有时候是[3:0],有时候是[0:3]。这其实是MSB与LSB的区别,互相之间是左右颠倒的
// 4-to-1 multiplexer
module mux16to1(W, S16, f);
// ...
task mux4to1;
input [3:0] W;
input [1:0] S;
output Result;
begin
Result = W[S];
end
endtask
// ...
endmodule
后面讲了multiplexer, decoder, encoder, comparator,感觉没啥卵用,就不写了
莫名其妙的,并没有Lecture 8
本节主要讲了加法器,以及overflow(溢出)
然而看起来没啥用,所以在此复习一下以前的关于boolean的运算
异或符合结合律(associative rule)
2's complement
先按位取反,然后+1
2 = 0010
1101
-2 = 1110 (1101 + 1)
0001
2 = 0010 (0001 + 1)
module fulladd(Cin, x, y, s, Cout);
input Cin, x, y;
output s, Cout;
xor(s, x, y, Cin);
and(z1, x, y);
and(z2, x, Cin);
and(z3, y, Cin);
or(Cout, z1, z2, z3);
endmodule
module fulladd(Cin, x, y, s, Cout);
input Cin, x, y;
output s, Cout;
assign s = x ^ y ^ Cin;
assign Cout = (x & y) | (x & Cin) | (y & Cin);
endmodule
module adder4(carryin, X, Y, S, carryout);
input carryin;
input [3:0] X, Y;
output [3:0] S;
output carryout;
wire [3:1] C;
fulladd stage0(carryin, X[0], Y[0], S[0], C[1]);
fulladd stage1(C[1], X[1], Y[1], S[1], C[2]);
fulladd stage2(C[2], X[2], Y[2], S[2], C[3]);
fulladd stage3(C[3], X[3], Y[3], S[3], carryout);
endmodule
module addern(carryin, X, Y, S, carryout);
parameter n = 32;
input carryin;
input [n-1:0] X, Y;
output reg [n-1:0] S;
output reg carryout;
reg [n:0] C;
ingeter k;
always@(X, Y, carryin) begin
C[0] = carryin;
// 此处相当于多次1-bit full-adder (continuous assignment)
for (k=0; k<n; k=k+1) begin
S[k]=X[k] ^ Y[k] ^ C[k];
C[k+1] = (X[k] & Y[k]) | (X[k] & C[k]) | (Y[k] & C[k]);
end
carryout = C[n];
end
endmodule
module addern(carryin, X, Y, S, carryout, overflow);
parameter n = 32;
input carryin;
input [n-1:0] X, Y;
output reg [n-1:0] S;
output reg carryout, overflow;
reg [n:0] C;
ingeter k;
always@(X, Y, carryin) begin
{carryout, S} = X + Y + carryin;
// 看不懂overflow是什么鬼
overflow = carryout ^ X[n-1] ^ Y[n-1] ^ S[n-1];
end
endmodule
BCD就是写成二进制,然后每四位本应表示十六进制,但是在此表示十进制
module bcdadd(Cin, X, Y, S, Cout);
input Cin;
input [3:0] X, Y;
output reg [3:0] S;
output reg Cout;
reg [4:0] Z;
always@(X, Y, Cin) begin
Z = X + Y + Cin;
if (Z < 10)
{Cout, S} = Z;
else
{Cout, S} = Z + 6;
end
endmodule
7+5=12
7=0111
5=0101
1100>1010
1100+0110=10010
0001 0010 -> 12
本节讲了:
Counter
= / <= 在以上module中的应用
感觉没啥好总结的,跳过之
Sequential circuits are called finite state machines (FSM)(有限状态机)
Moore type: 输出只与state有关
Mealy type: 输出与state以及input有关
input w, output z
z只有在上两个clock中w都是1的时候才为1,否则为0
Clockcycle | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
w | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
z | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 |
input w, output z
z只有在连续两次w都为1的时候才为1,否则为0
Clockcycle | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
w | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 |
z | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
感觉判断Moore和Mealy的方法,就是看input能否在当前clock直接对output造成影响。如果可以,是Mealy,否则为Moore
对于状态机的state table,以及借助那个什么表格来求Y1、Y2以及z的表达式,会在以后进行专题讲解
完全不知所云……