当前位置:   article > 正文

FPGA学习——HDLBits网站刷题笔记整理(4)_本关任务:采用case分支结构,完成一个4位优先权编码器的建模。对于输入in,输出其中

本关任务:采用case分支结构,完成一个4位优先权编码器的建模。对于输入in,输出其中

程序

组合逻辑always模块

always模块有两种:
组合:always@(*)
时序:always@(posedge clk)
组合逻辑always模块和assign模块赋值是等价的,使用哪一种完全看哪一种更为方便。always模块内可有更丰富的状态,如if-then,case等,但是不能有连续赋值语句assign。
assign赋值语句的左边一般为wire型,always赋值语句的左边一般为reg型。
always是一个过程块,后面通常接@再接敏感列表。时序逻辑,一般写作always@(posedge clk)也就是上升沿敏感,每次时钟上升沿的时候开始执行always当中的过程块,当然并不是都是时钟敏感的,比如说组合逻辑电路通常可以写成always@(**),只要always块中的任意变量发生变化都会触发always块。
题目:使用赋值语句assign和组合always块两种方式构建与门。
答案:

module top_module(a, b, out_assign, out_alwaysblock);
    input a, 
    input b,
    output wire out_assign,
    output reg out_alwaysblock
    assign out_assign = a & b;//连续赋值语句
    always @(*) begin     //组合always赋值
        out_alwaysblock = a & b; 
    end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

时序逻辑always模块

时序always块可像组合always块那样生成电路,同时也会生成一系列的触发器,寄存器等,因为输出要等到下个时钟延才能输出。
阻塞赋值 与 非阻塞赋值
verilog中有三种赋值方式:
1)连续赋值(assign x=y;),只能在always块外使用。
2)阻塞赋值(x=y;),只能在always块内使用。
3)非阻塞赋值(x<=y;)只能在always块内使用。
在组合逻辑的always块中(always @(*))使用阻塞赋值语句;在时序逻辑的always块中(always @(posedge clk))使用非阻塞赋值语句。
题目:使用赋值语句、组合always块和时序always块三种方式构建一个异或门。
答案:

module top_module(clk, a, b, out_assign, out_always_comb,out_always_ff);
    input clk,
    input a,
    input b,
    output wire out_assign,
    output reg out_always_comb,
    output reg out_always_ff   
	assign out_assign = a ^ b;  //连续赋值语句
    always @(*) begin         //组合always赋值语句
        out_always_comb = a ^ b;
    end
    always @(posedge clk) begin  //时序always赋值语句
        out_always_ff <= a ^ b;
    end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

IF语句

一个if语句会产生一个2选1的数据选择器,需注意的是,并不是if选择的那路数据才被实现成电路模式,而是if和else两路都被实现为电路形式然后用选择器选择输出。
条件(if)语句用于控制执行语句要根据条件判断来确定是否执行。
条件语句用关键字 if 和 else 来声明,条件表达式必须在圆括号中。
if语句使用结构如下:

if(congdition)          ture_statement;
else if (congdition1)   ture_statement1;
else if (congdition2)   ture_statement2;
else                    default_statement;
  • 1
  • 2
  • 3
  • 4

if 语句执行时,如果 condition为真,则执行true_statement ;如果 condition1为假,condition2为真,则执行 true_statement2;依次类推。
else if 与 else 结构可以省略,即可以只有一个 if 条件判断和一组执行语句 ture_statement1 就可以构成一个执行过程。
else if 可以叠加多个,不仅限于 1 或 2 个。
ture_statement等执行语句可以是一条语句,也可以是多条。如果是多条执行语句,则需要用 begin 与 end 关键字进行说明。
if的两种方式:

always @(*) begin
    if (condition) begin
        out = x;
    end
    else begin
        out = y;
    end
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
assign out = (condition) ? x : y;
  • 1

IF中锁存器问题

锁存器(Latch)是数字逻辑电路中很重要的一种基本电路,常见的锁存器包括三个端口:数据输入口、数据输出口、使能端。当使能端为高电平时,输入口的数据直接送到输出口,此时输入输出口可以看成是直接连通的;当使能端为低电平时,输出口的数据保持之前的数据不变,无论输入口的数据怎么变化,输出都保持不变,就是把原来的状态锁存下来了(所以才叫锁存器)。锁存器与触发器的区别在于:锁存器是电平触发,而触发器是边沿触发。锁存器在不锁存数据时,输出随输入变化;但一旦数据锁存时,输入对输出不产生任何影响。
在FPGA电路设计中,不规范的描述语言可能会产生意想不到的锁存器,而设计者往往并没有注意到自己的设计会被综合出锁存器,导致综合出的电路出现逻辑错误。
产生锁存器的情况一般有两种:
1)if…else…结构中缺少else
2)case结构中的分支没有包含所有情况并且没有default语句
所以当我们使用if语句或者case语句时,我们必须考虑到所有情况并给对应情况的输出进行赋值,就意味着我们要为else或者default中的输出赋值。

Case语句

在Verilog中,case语句与if-elseif-else相近,与c语言中的switch差别较大,如下:

always @(*) begin     // This is a combinational circuit
    case (in)
      1'b1: begin 
               out = 1'b1;  // begin-end if statement >1
            end
      1'b0: out = 1'b0;
      default: out = 1'bx;
    endcase
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

1)case语句以case开始,每个case的选项以分号结束,没有开关。
2)每个case项只能执行一条语句。这使得在C中使用的“break”是不必要的。但这意味着如果你需要不止一个语句,你必须使用begin…end。
3)允许重复(部分重叠)案例项目。使用第一个匹配的。C不允许重复的case项。
题目:6选1选择器
答案:

module top_module (sel, data0, data1, data2, data3, data4, data5, out);
    input [2:0] sel, 
    input [3:0] data0,
    input [3:0] data1,
    input [3:0] data2,
    input [3:0] data3,
    input [3:0] data4,
    input [3:0] data5,
    output reg [3:0] out   
    always@(*) begin  // This is a combinational circuit
        case(sel)
            3'b000:out=data0;
            3'b001:out=data1;
            3'b010:out=data2;
            3'b011:out=data3;
            3'b100:out=data4;
            3'b101:out=data5;
            default:out=3'b0;
        endcase
    end

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

优先编码器

允许同时在几个输入端有输入信号,编码器按输入信号排定的优先顺序,只对同时输入的几个信号中优先权最高的一个进行编码。
题目:构建一个4位优先级编码器。 对于此问题,如果所有输入位都不为高(即输入为零),则输出零。 请注意,一个4位数字具有16种可能的组合。
答案:按照常规思路,可以列出每一种情况,分别进行赋值,该方法对于位数不多的编码器而言,可行。但对于多位的编码器不适合,代码太多且繁琐。
因为case允许重复(部分重叠)案例项目。使用第一个匹配的。 从低位到高位去比较in中是否有数据位为1,但只执行首次匹配的操作。很大程度上简化了代码。

module top_module (
    input [3:0] in,
    output reg [1:0] pos  );
    always @(*) begin
        case(1)
            in[0]:pos = 0;
            in[1]:pos = 1;
            in[2]:pos = 2;
            in[3]:pos = 3;
            default:pos = 0;
        endcase
    end
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

casez实现优先编码器

casez可以减少需要比较的案例项目,在比较中,将值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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

case语句的行为就好像每个项都是按顺序检查的(实际上,它更像是生成一个巨大的真值表,然后生成gates)。注意如何有某些输入(例如,4’b1111)将匹配多个case项。选择第一个匹配项(因此4’b1111匹配第一个项,out=0,但不匹配后面的任何项)。
还有一个类似的casex,它将x和z都视为不在乎。我觉得用它来代替凯斯没什么用。
数字?是z的同义词。所以2’bz0和2’b?0是一样的。

避免产生锁存器

为避免产生锁存,必须在所有可能的条件下为所有输出分配一个值。仅仅有一个默认案例是不够的。在所有四种情况和默认情况下,必须为所有四个输出指定一个值。这可能涉及许多不必要的输入。解决这个问题的一个简单方法是在case语句之前为输出分配一个“默认值”:

always @(*) begin
    up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
    case (scancode)
        ... // Set to 1 as necessary.
    endcase
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这种类型的代码确保在所有可能的情况下为输出赋值(0),除非case语句重写赋值。这也意味着default:case项变得不必要。

以上是HDLBits Verilog语言刷题网站中的Procedures部分,后续部分会继续更新。对一些基础性知识点进行归纳总结,有错误请指正。仅供学习参考,谢谢!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/915776
推荐阅读
相关标签
  

闽ICP备14008679号