跳转至

实验练习

说明

  1. 每一次实验我们会为大家准备若干练习题目。不同的题目有着不同的难度,请大家量力而行;
  2. 你可以查阅任何开源资料完成实验练习,但不能直接抄袭。一经发现,我们将取消所有抄袭参与者本次的实验成绩。情节特别严重的,我们将按照学校的有关规定进行处理。
  3. 部分题目我们提供了代码框架,你需要在框架指定的位置完成代码内容。你也可以自由修改框架代码,但需要根据题目要求完成练习。

Verilog 扣分细则

在 Lab1 的实验练习开始之前,我们额外补充一些需要注意的内容。我愿称之为『扣分细则』。

什么?为什么会有扣分细则?这是因为 Verilog 开发中的问题有 90% 以上源于代码编写不规范。为了保证大家后续实验的正常进行,我们在这里明确一些『雷区』,希望大家能够在编程过程中加以注意。

下面的内容是被禁止的:

不要使用基于位置的端口关联

在进行模块例化时,无论端口数目多少,请一定使用基于端口名称的关联。

这是一个典型的反例:

MyModule mymodule(clk, rst, signal1, signal2, signal3, signal4, signal5, signal6, signal7, still_signal, tons_if_signals, i, just, want, to, write, something, here, to_, show, you, how, annoying, the, location_based, correspondence, is, signals_again, bu, la, bu_, la_, bu__, la__, bu___, la___, bu____, la____, ok, that_s, enough);

不要混用阻塞赋值与非阻塞赋值

阻塞赋值 = 只用在 assignalways @(*) 的组合逻辑中,非阻塞赋值 <= 只用在 always @(posedge clk) 的时序逻辑中。请不要在错误的场景下使用,甚至二者混用。

这是一个典型的反例:

assign a <= 1;

always @(posedge clk)
    a = a + 1;

always @(*) begin
    a <= a + 1;
    if (b)
        a = 0;
end

不要在设计文件中使用 for 循环

Verilog 的 for 循环与 C 语言不一样,因此请不要在设计文件中使用 for 循环。

下面的内容是我们鼓励的:

一个文件里只声明一个 module

这是一个很无理的要求,因为有些模块只有不到 10 行!

事实上,这个规范并不是针对大家本学期的数电实验,而是针对大家下学期组成原理的实验。如果我们把 module 单独写一个文件,我们就可以在 Vivado 中通过点击直接进入这个文件,提升开发效率。另外,如果我们在一个文件中写多个模块,很容易导致找 bug 时在不同模块之间切换时出现错误。所以,建议大家还是分文件写模块吧!

良好的缩进与对齐习惯

为了增强代码可读性,我们鼓励大家养成良好的缩进与对齐习惯。

  1. begin/end 以及括号中的代码要进行一个 Tab 的缩进;end 与开启 begin...end 行的字符左对齐;case 语句对每种 case 冒号前的部分进行对齐。例如:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    // 括号中的代码需要缩进
    cache_memory way0 (
        .addra (w_index), // Tab 缩进
        .clka (clk),
        .dina (mem_din),
        .ena (mem_en[0]),
        .wea (mem_we),
        .addrb (r_index),
        .doutb (mem_dout0)
    ); // 分号不要忘记
    
    // begin...end 中的代码需要缩进
    always @(*) begin
        case (wrt_data_sel) // Tab 缩进
            1'b0: mem_din = w_data_AXI;
            1'b1: begin
                case(wrt_type) // Tab 缩进
                    BYTE: mem_din = {64{w_data_CPU[7:0]}}; // Tab 缩进
                    HALF: mem_din = {32{w_data_CPU[15:0]}};
                    WORD: mem_din = {16{w_data_CPU}};
                    default: mem_din = 0;
                endcase // 与 17 行的 case 对齐
            end // 与 1'b1 对齐,因为这个 end 对应 16 行的 begin
        endcase // 与 14 行的 case 对齐
    end // 与 always 对齐
    
  2. 在双目运算符的两侧填加空格,如:

    assign hit[3] = (tag == tag_3) && vld_3; // 赋值运算符、等于运算符以及逻辑与运算符
    
  3. 模块声明的部分至少要和最长的 output 对齐,短于它的要在右边补空格。这样写的好处是,使用多点编辑操作同一列时非常方便(直接 ctrl+alr+↑ 或 ctrl+alr+↓ 即可)。例如:

    module Check_Data_SEG_SEL (
        input [31:0]       check_data_if,
        input [31:0]       check_data_id,
        input [31:0]       check_data_ex,
        input [31:0]       check_data_mem,
        input [31:0]       check_data_wb,
        input [31:0]       check_data_hzd,
        input [2:0]        check_addr,
        output reg [31:0]  check_data
    );
    

    这里实际上添加了额外的空格。当然,你也可以将位宽部分也对齐,例如下面这样:

    module Check_Data_SEG_SEL (
        input      [31:0]  check_data_if,
        input      [31:0]  check_data_id,
        input      [31:0]  check_data_ex,
        input      [31:0]  check_data_mem,
        input      [31:0]  check_data_wb,
        input      [31:0]  check_data_hzd,
        input      [ 2:0]  check_addr,
        output reg [31:0]  check_data
    );
    

有意义的变量命名

除了要求的最外层的接口名称,内部名称应该具有意义,不要怕名字长,如:

assign index = read_address[11:6];  // 你也可以简写为 r_addr,但不要只写一个 r

必做内容

每一名同学都需要完成必做部分的内容。

题目 1:向量翻转(2 分)

本题来自于 Verilog OJ ID-16。你可以在该平台上验证自己的设计。

请编写 Verilog 代码,将 8bit 的输入信号按位翻转,并输出到输出端口。该过程如下图所示:

Image title

我们已经为你准备了可用的框架代码:

module top_module( 
    input  [7:0]          in,
    output [7:0]          out
);
// Your codes should start from here.
// ......
// End of your codes.
endmodule

题目 2:最大值问题(3 分)

下面的 Verilog 代码片段实现了两个数取最大值的功能:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
module MAX2 (
    input      [7:0]            num1, num2,
    output reg [7:0]            max
);
always @(*) begin
    if (num1 > num2)
        max = num1;
    else
        max = num2;
end
endmodule

请据此完成下面的问题。

  1. 请使用 assign 语句重新完成该模块的功能。代码框架我们已经为你写好:

    module MAX2 (
        input  [7:0]         num1, num2,
        output [7:0]         max
    );
    // Your codes should start from here.
    // ......
    // End of your codes.
    endmodule
    
  2. 现在我们需要获得三个数的最大值。请参考 MAX2 的代码,使用 alwaysif-else 语句完成该功能。代码框架我们已经为你写好:

    module MAX3 (
        input       [7:0]         num1, num2, num3,
        output reg  [7:0]         max
    );
    // Your codes should start from here.
    // ......
    // End of your codes.
    endmodule
    
  3. 现在我们需要获得三个数的最大值。请在下面的框架中通过例化 MAX2 模块实现该功能。

    module MAX3 (
        input   [7:0]         num1, num2, num3,
        output  [7:0]         max
    );
    // Your codes should start from here.
    // ......
    // End of your codes.
    endmodule
    

题目 3:1 的个数(3 分)

给定一个位宽为 3 的信号 in,编写 Verilog 代码以输出其中为 1 的位的数目。例如:如果 in = 3'b011,则模块输出 2'd2;如果 in = 3'b111,则模块输出 2'd3。

我们已经为你准备了可用的框架代码:

module Count4Ones(
    input       [2:0]         in,
    output reg  [1:0]         out
);
// Your codes should start from here.
// ......
// End of your codes.
endmodule

选择性必做内容

选择性必做内容是针对不同层次学生设计的分层内容。不同难度的题目对应不同的分值,请大家根据自身实际情况进行选择。

请在下面的题目中任选一题完成。多选按选择的第一题计分。

题目 1:Logisim 使用(2 分)

1.请根据 Logisim 使用教程中的内容,使用 Logisim 搭建一个 1bit 宽度的二选一选择器并封装。你可以参考我们在 Lab1 实验教程中介绍的电路结构进行设计。

2.请使用上面封装的电路搭建一个 4bits 宽度的二选一选择器。

题目 2:Verilog 运算符(2 分)

阅读以下 Verilog 代码,写出当 a = 8’b0011_0011, b = 8’b1111_0000 时各输出信号的值。

module test( 
    input  [7:0]        a, b, 
    output [7:0]        c, d, e, f, g, h, i, j, k, l
); 
assign c = a & b; 
assign d = a || b; 
assign e = a ^ b; 
assign f = ~a; 
assign g = {a[2:0], b[3:0], {1'b1}}; 
assign h = b >>> 3; 
assign i = &b; 
assign j = (a > b) ? a : b; 
assign k = a - b; 
assign l = !a;
endmodule

选做内容

选做内容为扩展内容,不计入实验成绩。大家可以根据兴趣自行完成。

题目 1:Verilog 数组

Verilog 支持对于数组的声明。请自行查阅有关资料,编写 Verilog 代码,声明一个由 16 个位宽为 32 的 reg 型变量组成的数组。

题目 2:带参数例化

除了我们正文中介绍的使用 # 在例化时传递参数,Verilog 还允许使用 defparam 关键字进行参数设定。请自行查阅有关资料,简述这两种方法的不同之处以及使用场景。


最后更新: October 13, 2023

评论

Authors: wintermelon008