Procedures (比如always) 为描述电路提供另一种语法:
always@(*)
always@(posedge clock)
always 块内部代码的语法与外部的不懂,有更丰富的语句集,如 if-then,case 不能包含连续赋值
assign out1 = a & b | c ^ d;
always @(*) out2 = a & b | c ^ d;
对于组合的 always 块,始终使用( * )的敏感度列表。明确列出信号很容易出错(如果你错过了一个),并且在硬件综合时会被忽略。如果您明确指定灵敏度列表并错过了一个信号,则合成硬件的行为仍将与指定( * )一样,但模拟不会也不匹配硬件的行为。(在 SystemVerilog 中,使用always_comb。)
关于 wire 与 reg 的注意事项:assign 语句的左侧必须是net类型(例如,wire),而过程赋值(在 always 块中)的左侧必须是变量类型(例如,reg)。这些类型(wire vs. reg)与合成的硬件无关,只是 Verilog 用作硬件模拟语言时留下的语法。
两个方式写 AND 与门
Verilog 中有三种类型的赋值:
在组合的always 块中,使用块分配。在时钟控制的always 块中,使用非阻塞分配。
//使用三种方式实现XOR
两种方式实现二选一数字选择器
避免产生锁存器
always @(*) begin // This is a combinational circuit
case (in)
1'b1: begin
out = 1'b1; // begin-end if >1 statement
end
1'b0: out = 1'b0;
default: out = 1'bx;
endcase
end
4位优先级编码器,从低位开始,先是1的位置被输出
如果 case 语句中的 case 项支持“忽略”位,这就是z的情况:它在比较中将具有值z的位视为不关心。
可以这样实现上一个练习中的 4 输入优先级编码器:
always @(*) begin
casez (in[3:0])
4'bzzz1: out = 0; // in[3:1] can be anything
4'bzz1z: out = 1;
4'bz1zz: out = 2;
4'b1zzz: out = 3;
default: out = 0;
endcase
end
case 语句的行为就好像每个项目都是按顺序检查的(实际上是一个很大的组合逻辑函数)。多个项都符合时候,会优先匹配第一个匹配项。
还有一个类似的casex将x和z都视为无关。
符号?是z的同义词。所以2’bz0和2’b?0一样
明确指定优先级行为而不是依赖于案例项目的顺序可能不太容易出错。如下:
casez ( in [ 3 : 0 ])
4'bzzz1: ...
4'bzz10: ...
4'bz100: ...
4'b1000 : ...
default: ...
endcase
本题为实现一个8位的优先编码器
下面的代码风格可以确保在所有可能的情况下为输出分配一个值(0),除非 case 语句覆盖了分配。这可以在没有default: case 时候也避免创建锁存器
always @(*) begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
case (scancode)
... // Set to 1 as necessary.
endcase
end
Verilog 有一个三元条件运算符 ( ? : )
eg:
(0 ? 3 : 5) // 这是 5,因为条件为假。
(sel ? b : a) // 由 sel 选择的 a 和 b 之间的 2 对 1 多路复用器。
always @(posedge clk) // 一个 T 型触发器
q <= toggle ? ~q : q;
assign out = ena ? q : 1’bz; // 一个三态缓冲区
((sel[1:0] == 2’h0) ? a : // 3 对 1 多路复用器
(sel[1:0] == 2’h1) ? b :
c )
四个数求最小值
创建一个对一个向量的所有位进行操作的逻辑
归约运算符可以对向量的位进行 AND、OR 和 XOR,产生一位输出:
& a[3:0] // 与:a[3]&a[2]&a[1]&a[0]。相当于 (a[3:0] == 4'hf)
| b[3:0] // 或:b[3]|b[2]|b[1]|b[0]。相当于 (b[3:0] != 4'h0)
^ c[2:0] // 异或:c[2]^c[1]^c[0]
这些是只有一个操作数的一元运算符(类似于 NOT 运算符 ! 和 ~)。您还可以反转这些输出以创建 NAND、NOR 和 XNOR 门,例如(~& d[7:0])。
奇偶校验
100个与 或 异或 门
100bit向量 反转顺序
255个人计数
例化100个全加器,generate for 语句 或者实例化数组
//加法器级联 (实例化数组版本)
module add(
input a,
input b,
input cin,
output cout,
output sum
);
always @(*) begin
sum = a + b +cin;
cout = ((a|b)&cin)||((cin|b)&a)||((a|cin)&b);
end
endmodule
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
reg [99:0] cout1 = 99'd0;
// assign cout = cout1[99];
assign cout = cout1;
add add1[99:0](
.a(a[99:0]),
.b(b[99:0]),
.cin({cout1[98:0],cin}),
.cout(cout1[99:0]),
.sum(sum[99:0])
);
endmodule## Bcdadd100
利用例化100个bcd_fadd的 BCD 一位加法器
生成100位的bcd
两个四通道与非门
真值表画卡诺图写assign
A=B时候输出1否则输出0
模块 A 应该实现函数z = (x^y) & x。实现这个模块。
module top_module (input x, input y, output z);
assign z = (x^y) & x;
endmodule
模块实现异或非
module top_module ( input x, input y, output z );
assign z = ~(x^y);
endmodule
使用Mt2015 q4a和Mt2015 q4b的模块生成如下逻辑
当接到电话时。,您的电路必须打开振铃器 ( ) 或电机 ( ),但不能同时打开两者。如果手机处于振动模式 ( ),请打开电机。否则,打开铃声。
module top_module (
input ring,
input vibrate_mode,
output ringer, // Make sound
output motor // Vibrate
);
assign motor = ring&vibrate_mode;
assign ringer = ring&(~vibrate_mode);
endmodule
加热/冷却恒温器控制加热器(冬季)和空调(夏季)。实施一个可以根据需要打开和关闭加热器、空调和鼓风机的电路。
恒温器可以处于以下两种模式之一:加热 ( mode = 1) 和冷却 ( mode = 0)。在制热模式下,当天气太冷时打开加热器(too_cold = 1),但不要使用空调。在制冷模式下,空调过热时打开空调(too_hot = 1),但不要打开加热器。当加热器或空调打开时,还要打开风扇以循环空气。此外,fan_on = 1即使加热器和空调已关闭,用户也可以请求打开风扇 (fan_on = 1 )。
总感觉这智障题看不起我
module top_module (
input too_cold,
input too_hot,
input mode,
input fan_on,
output heater,
output aircon,
output fan
);
assign heater = mode&too_cold;
assign aircon = (~mode)&(too_hot);
assign fan = mode&too_cold|(~mode)&(too_hot)|fan_on;
endmodule
“人口计数”电路计算输入向量中“1”的数量。为 3 位输入向量构建人口计数电路。
module top_module(
input [2:0] in,
output [1:0] out );
assign out = in[0]+in[1]+in[2];
endmodule
在 [3:0] 中给定一个四位输入向量。我们想知道每个位与其相邻位的一些关系:
out_both:此输出向量的每个位都应指示相应的输入位及其左侧的邻位(较高的索引)是否都是“1” 。例如,out_both[2]应该表明in[2]和in[3]是否都为 1。由于in[3]左边没有邻居,所以答案很明显,所以我们不需要知道out_both[3 ]。
out_any:此输出向量的每个位应指示相应的输入位及其右侧的邻居是否为“1”。例如,out_any[2]应该指示in[2]或in[1]是否为 1。由于in[0]右侧没有邻居,因此答案很明显,因此我们不需要知道out_any[0 ]。
out_different:此输出向量的每个位都应指示相应的输入位是否与其左侧的邻居不同。例如,out_diff[2]应该指示in[2]是否与in[3]不同。对于这部分,将向量视为环绕,因此in[3]左侧的邻居是in[0]。
module top_module(
input [3:0] in,
output [2:0] out_both,
output [3:1] out_any,
output [3:0] out_different );
assign out_different [3] = in[3]^in[0];
genvar i;
generate for (i =0;i<3 ;i++)
begin: both
assign out_both[i] = in[i+1]&in[i];
assign out_any[i+1] = in[i]|in[i+1];
assign out_different [i] = in[i+1]^in[i];
end
endgenerate
endmodule
逻辑和Gatesv一致,门扩充成了100个 ,改下角标即可
二选一数选,sel=0, a. sel=1, b.
module top_module(
input a, b, sel,
output out );
assign out = (sel)?b:a;
endmodule
sel=0 chooses a, sel=1 chooses b,9:15所有输出都置1
module top_module(
input [15:0] a, b, c, d, e, f, g, h, i,
input [3:0] sel,
output [15:0] out );
always@(*)begin
case(sel)
16'h00: out = a;
16'h01: out = b;
16'h02: out = c;
16'h03: out = d;
16'h04: out = e;
16'h05: out = f;
16'h06: out = g;
16'h07: out = h;
16'h08: out = i;
default: out = 16'hff;
endcase
end
endmodule
256选一 数选
//256选一数选
module top_module(
input [255:0] in,
input [7:0] sel,
output out );
assign out = in[sel];
endmodule
256*4选4
module top_module(
input [1023:0] in,
input [7:0] sel,
output [3:0] out );
assign out[3:0] = in[sel*4+:8];// sel*4开始向上取8位,verilog不支持上下都是变量,所以要这么写
endmodule
半加器,没cin
module top_module(
input a, b,
output cout, sum );
assign sum = a+b;
assign cout = a&b;
endmodule
全加器
module top_module(
input a, b, cin,
output cout, sum );
assign cout = (a&b)|(b&cin)|(a&cin);
assign sum = a+b+cin;
endmodule
三位全加器
module adder(
input a, b, cin,
output cout, sum );
assign cout = (a&b)|(b&cin)|(a&cin);
assign sum = a+b+cin;
endmodule
module top_module(
input [2:0] a, b,
input cin,
output [2:0] cout,
output [2:0] sum );
// wire [2:0]cout1 ;
adder add[2:0](
.a(a[2:0]),
.b(b[2:0]),
.cout(cout[2:0]),
.cin({cout[1:0],cin}),
.sum(sum[2:0])
);
endmodule
实现加法器
module adder(
input a, b, cin,
output cout, sum );
assign cout = (a&b)|(b&cin)|(a&cin);
assign sum = a+b+cin;
endmodule
module top_module (
input [3:0] x,
input [3:0] y,
output [4:0] sum);
wire [3:0] cout;
assign sum[4] = cout[3];
adder add[3:0](
.a(x[3:0]),
.b(y[3:0]),
.cout(cout[3:0]),
.cin({cout[2:0],1'b0}),
.sum(sum[3:0])
);
endmodule
s = a+b ,overflow是溢出位
8位有符号位最高是符号位 ,所以需要确定什么时候算溢出
两个正数相加,肯定是第9位为1时候溢出
两个负数相加,也是第9位为1
一正 一负,那就是,是不是不可能溢出
module top_module (
input [7:0] a,
input [7:0] b,
output [7:0] s,
output overflow
); //
wire signed [7:0] a1;// = a;
wire signed [7:0] b1;// = b;
wire signed [7:0] s1;
assign a1 = a;
assign b1 = b;
assign s1 = a+b;
assign s = a+b;
assign overflow = (((a1>0)&&(b1>0)&&(s1<0))||((a1<0)&&(b1<0)&&(s1>0)))?1:0;
endmodule
4位bcd相加
给了一个Bcd_fadd,写一个四位的
module bcd_fadd (
input [3:0] a,
input [3:0] b,
input cin,
output cout,
output [3:0] sum );
module top_module (
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
reg [3:0] cout1;
assign cout = cout1[3];
bcd_fadd bcd[3:0](
.a(a[15:0]),
.b(b[15:0]),
.cin({cout1[2:0],cin}),
.cout(cout1[3:0]),
.sum(sum[15:0])
);
endmodule
从这里开始说是要介绍卡诺图
我觉得他瞧不起我
module top_module(
input a,
input b,
input c,
output out );
assign out = b |((~b)&c) |(a&(~b)&(~c));
endmodule
module top_module(
input a,
input b,
input c,
input d,
output out );
assign out = ((~a)&(~b)&(~c))|((~a)&(~d)&(c))|((d)&(b)&(c))|((a)&(~b)&(d))|((~a)&(b)&(~c)&(~d))|((a)&(~b)&(~c)&(~d));
endmodule
module top_module(
input a,
input b,
input c,
input d,
output out );
assign out = a|((~a)&(~b)&(c));
endmodule
对角线卡诺图 如下
module top_module(
input a,
input b,
input c,
input d,
output out );
assign out = a^b^c^d;
endmodule
SOP: 划1
POS: 划0
module top_module (
input a,
input b,
input c,
input d,
output out_sop,
output out_pos
);
assign out_sop = (c&d)|((~a)&(~b)&(c)&(~d));
assign out_pos = ~((~c)|((a)&(c)&(~d))|((b)&(c)&(~d)));
endmodule
module top_module (
input [4:1] x,
output f );
assign f = ((~x[1])&x[3])|((x[2])&(~x[3])&x[4]);
endmodule
module top_module (
input [4:1] x,
output f
);
assign f = (~x[1])&x[3]|x[3]&(x[1])&(x[2]^~x[4])|(~x[2])&(~x[3])&(~x[4]);
endmodule
module top_module (
input c,
input d,
output [3:0] mux_in
);
assign mux_in[0] = c|d;
assign mux_in[1] = 1'b0;
assign mux_in[2] = ~d;
assign mux_in[3] = c&d;
endmodule
latches:锁存器
Flip-Flops:触发器
二者区别:
锁存器,是由电平触发,面积比ff小,速度比ff快,电平触发,非同步设计,受布线延迟影响较大,很难保证输出没有毛刺产生,latch将静态时序分析变得极为复杂
触发器,是时钟边沿触发,可存储1bitdata,是register的基本组成单位,同步设计,不容易受毛刺的印象,时序分析简单,面积比latch大,消耗的门电路比latch多
锁存器在ASIC设计中应该说比ff要简单,但是在FPGA的资源中,大部分器件没有锁存器这个东西,所以需要用一个逻辑门和ff来组成锁存器,这样就浪费了资源。
锁存器比FF快,所以用在地址锁存是很合适的,不过一定要保证所有的latch信号源的质量,锁存器在CPU设计中很常见,正是由于它的应用使得CPU的速度比外部IO部件逻辑快许多。latch完成同一个功能所需要的门较触发器要少,所以在asic中用的较多。
写一个D 触
module top_module (
input clk, // Clocks are used in sequential circuits
input d,
output reg q );//
// Use a clocked always block
// copy d to q at every positive edge of clk
// Clocked always blocks should use non-blocking assignments
always@(posedge clk) begin
q <= d;
end
endmodule
写一个8D触,输入定义变化,always内代码同上。
module top_module (
input clk,
input reset, // Synchronous reset
input [7:0] d,
output [7:0] q
);
always@(posedge clk ) begin
if(reset)
q <= 8'b0;
else
q <= d;
end
endmodule
下降沿触发的8d触 ,复位值为0x34
module top_module (
input clk,
input reset,
input [7:0] d,
output [7:0] q
);
always@(negedge clk ) begin
if(reset)
q <= 8'h34;
else
q <= d;
end
endmodule
8 D FF,High reset 异步复位 上升沿触发
module top_module (
input clk,
input areset, // active high asynchronous reset
input [7:0] d,
output [7:0] q
);
always@(posedge clk ,posedge areset) begin
if(areset)
q <= 8'b0;
else
q <= d;
end
endmodule