HDL-Bits 刷题记录 01

Always块

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 用作硬件模拟语言时留下的语法。

alwaysblock1

两个方式写 AND 与门

Verilog 中有三种类型的赋值:

  • 连续赋值(assign x = y;)。只能在不在过程中使用(“总是阻塞”)。
  • 程序块分配:( x = y; )。只能在程序内部使用。
  • 程序非阻塞赋值:( x <= y; )。只能在程序内部使用。

在组合的always 块中,使用块分配。在时钟控制的always 块中,使用非阻塞分配。

alwaysblock2

//使用三种方式实现XOR

Always if

两种方式实现二选一数字选择器

Always if2

避免产生锁存器

Always case

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

Always case2

4位优先级编码器,从低位开始,先是1的位置被输出

Always casez

如果 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位的优先编码器

Always nolatches

下面的代码风格可以确保在所有可能的情况下为输出分配一个值(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

conditional

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 )

四个数求最小值

Reduction

创建一个对一个向量的所有位进行操作的逻辑
归约运算符可以对向量的位进行 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])。

奇偶校验

Gates100

100个与 或 异或 门

Vector100r

100bit向量 反转顺序

Popcount255

255个人计数

Adder100i

例化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

Circuits

Combinational 逻辑

7420

两个四通道与非门

Truthtable1

真值表画卡诺图写assign

Mt2015 eq2

A=B时候输出1否则输出0

Mt2015 q4a

模块 A 应该实现函数z = (x^y) & x。实现这个模块。

module top_module (input x, input y, output z);
    assign z = (x^y) & x;
endmodule

Mt2015 q4b

模块实现异或非

module top_module ( input x, input y, output z );
    assign z = ~(x^y);
endmodule

Mt2015 q4

使用Mt2015 q4a和Mt2015 q4b的模块生成如下逻辑
Mt2015_q4.png

Ringer

当接到电话时。,您的电路必须打开振铃器 ( ) 或电机 ( ),但不能同时打开两者。如果手机处于振动模式 ( ),请打开电机。否则,打开铃声。

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

Thermostat

加热/冷却恒温器控制加热器(冬季)和空调(夏季)。实施一个可以根据需要打开和关闭加热器、空调和鼓风机的电路。

恒温器可以处于以下两种模式之一:加热 ( 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

Popcount3

“人口计数”电路计算输入向量中“1”的数量。为 3 位输入向量构建人口计数电路。

module top_module( 
    input [2:0] in,
    output [1:0] out );
    assign out = in[0]+in[1]+in[2];
endmodule

Gatesv

在 [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

Gatesv100

逻辑和Gatesv一致,门扩充成了100个 ,改下角标即可

Mux2to1

二选一数选,sel=0, a. sel=1, b.

module top_module( 
    input a, b, sel,
    output out ); 
    assign out = (sel)?b:a;
endmodule

Mux9to1v

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

Mux256to1

256选一 数选

//256选一数选
module top_module( 
    input [255:0] in,
    input [7:0] sel,
    output out );
    assign out = in[sel];

endmodule

Mux256to1v

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

Hadd

半加器,没cin

module top_module( 
    input a, b,
    output cout, sum );
    assign sum = a+b;
    assign cout = a&b;
endmodule

Fadd

全加器

module top_module( 
    input a, b, cin,
    output cout, sum );
    assign cout = (a&b)|(b&cin)|(a&cin);
    assign sum = a+b+cin;
endmodule

Adder3

三位全加器

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

Adder

实现加法器
m2014_q4j.png

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

ece241_2014_q1c

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

Adder100

Bcdadd4

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
卡诺图02
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
卡诺图3
module top_module(
    input a,
    input b,
    input c,
    input d,
    output out  ); 
    assign out = a|((~a)&(~b)&(c));
endmodule
卡诺图4

对角线卡诺图 如下
Kmap4.png

module top_module(
    input a,
    input b,
    input c,
    input d,
    output out  ); 
	assign out = a^b^c^d;
endmodule
卡诺图5 SOP POS

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
卡诺图6 m2014 q3

m2014_q3.png

module top_module (
    input [4:1] x, 
    output f );
    assign f = ((~x[1])&x[3])|((x[2])&(~x[3])&x[4]);
endmodule
卡诺图7 2012 q1g
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
卡诺图8

ece241_2014_q3.png

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 and Flip-Flops

latches:锁存器
Flip-Flops:触发器
二者区别:
锁存器,是由电平触发,面积比ff小,速度比ff快,电平触发,非同步设计,受布线延迟影响较大,很难保证输出没有毛刺产生,latch将静态时序分析变得极为复杂
触发器,是时钟边沿触发,可存储1bitdata,是register的基本组成单位,同步设计,不容易受毛刺的印象,时序分析简单,面积比latch大,消耗的门电路比latch多
锁存器在ASIC设计中应该说比ff要简单,但是在FPGA的资源中,大部分器件没有锁存器这个东西,所以需要用一个逻辑门和ff来组成锁存器,这样就浪费了资源。
锁存器比FF快,所以用在地址锁存是很合适的,不过一定要保证所有的latch信号源的质量,锁存器在CPU设计中很常见,正是由于它的应用使得CPU的速度比外部IO部件逻辑快许多。latch完成同一个功能所需要的门较触发器要少,所以在asic中用的较多。

Dff

写一个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
Dff8

写一个8D触,输入定义变化,always内代码同上。

Dff8r
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
Dff8p

下降沿触发的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
Dff8ar

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

define_mine

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值