跳转至

实验练习

说明

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

必做内容

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

题目 1:if 语句与锁存器(1 分)

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

有时候,语法正确的代码并不一定能产生功能正常的电路,一般来说都是因为不小心引入了锁存器造成的。例如下面的 Verilog 语句:

1
2
3
4
5
6
7
8
9
always @(*) begin
    if (cpu_overheated)
        shut_off_computer = 1;
end

always @(*) begin
    if (~arrived)
        keep_driving = ~gas_tank_empty;
end

Image title

为消除锁存器,我们应当使组合逻辑过程块中的条件完备,即 if 语句后应加上 else 语句。试修改上述两段代码,以消除锁存器。

输入格式

  • 输入信号 cpu_overheated, 位宽 1bit,控制 shut_off_computer 信号。
  • 输入信号 arrived, 位宽 1bit,控制 keep_driving 信号。
  • 输入信号 gas_tank_empty,位宽 1bit, 作为 keep_driving 的输入信号之一。

输出格式

  • 输出信号 shut_off_computer,位宽 1bit,要求 cpu_overheated 为真时输出 1'b1,反之输出 1'b0。
  • 输出信号 keep_driving,位宽 1bit,要求 arrived 为假时输出 ~gas_tank_empty,反之输出 1'b0。

代码框架如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
module top_module (
    input                       cpu_overheated,
    output  reg                 shut_off_computer,
    input                       arrived,
    input                       gas_tank_empty,
    output  reg                 keep_driving
);
    // Edit the code below
    always @(*) begin
        if (cpu_overheated)
            shut_off_computer = 1'b1;
    end

    always @(*) begin
        if (~arrived)
            keep_driving = ~gas_tank_empty;
    end
endmodule

题目 2:case 语句与锁存器(1 分)

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

假设您正在构建一个电路来处理游戏中 PS/2 键盘上的扫描码。现在给定接收到的扫描码的最后两个字节,您需要指示是否按下了键盘上的一个箭头键。这涉及到一个相当简单的映射,包含五种可能的情况:上、下、左、右,以及不属于任何一种。

Image title

您的电路有一个 16bits 输入和四个 1bit 输出,该电路识别这四个扫描码并确认正确的输出。为避免产生锁存,必须在所有情况下为四个输出指定一个值。这可能涉及许多不必要的输入。解决这个问题的一个简单方法是在 case 语句之前为输出分配一个『默认值』:

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

这种类型的代码确保在所有可能的情况下为输出赋值(0),除非 case 语句重写赋值。这也意味着 default 项变得不必要。请试着将上述代码补充完整,以实现期望的电路功能。

代码框架如下:

1
2
3
4
5
6
7
8
9
module top_module (
    input       [15:0]                  scancode,
    output reg                          left,
    output reg                          down,
    output reg                          right,
    output reg                          up
); 
// Write your codes here.
endmodule

题目 3:生成波形(2 分)

请编写仿真文件,生成下图所示的波形。时钟周期设定为 10ns,变量 c 的位宽自行指定(图中存在偏差,实际上变量 c 应在时钟上升沿变化)。图中的阴影部分代表电路状态不确定,你可以自行指定其状态。

Image title

题目 4:计数器 Pro(3 分)

这是我们在实验教程中展示的计数器代码:

Counter.v
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
module Counter #(
    parameter   MAX_VALUE = 8'd100
)(
    input                   clk,
    input                   rst,
    output                  out
);

reg [7:0] counter;
always @(posedge clk) begin
    if (rst)
        counter <= 0;
    else begin
        if (counter >= MAX_VALUE)
            counter <= 0;
        else
            counter <= counter + 8'b1;
    end
end

assign out = (counter == MAX_VALUE);
endmodule

现在,我们需要对其进行一点改进。

  1. 现在的计数器复位值是 0,最小值是 0,最大值是 MAX_VALUE。请修改代码,使得计数器的最小值也可以由模块参数 MIN_VALUE 指定。

  2. 在 1 的基础上,增加一个 1bit 输入信号 enable 用于控制计数器的工作状态。要求:enable 为高电平时,计数器在 MIN_VALUE 至 MAX_VALUE 之间正常工作;enable 为低电平时,counter 变量复位并保持在 0。从 enable 变为低电平开始到 counter 复位并保持在 0 的间隔不超过三个时钟周期。此外,rst 信号的优先级应当高于 enable 信号。

    你需要结合仿真波形证明自己设计的正确性。例如:下面是助教的仿真文件与结果:

    q4_tb.v
     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
    26
    27
    28
    29
    30
    31
    module q4_tb();
    reg clk, rst, en;
    wire out_TA;
    initial begin
        clk = 0; rst = 1; en = 0;
        #10;
        rst = 0;
        #10;
        en = 1;
        #20;
        en = 0;
        #20;
        en = 1;
        #20;
        rst = 1;
        #20;
        rst = 0;
        #200;
        en = 0;
    end
    always #5 clk = ~clk;
    Counter #(
        .MIN_VALUE(8'd10), 
        .MAX_VALUE(8'd13)
    ) counter (
        .clk(clk),
        .rst(rst),
        .enable(en),
        .out(out_TA)
    );
    endmodule
    

    Image title

选择性必做内容

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

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

题目 1:奇怪的代码(2 分)

下面是一段被加密的代码。请自行编写仿真文件,设计特定的输入,测试该模块的功能。

Foo.v
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
module Foo (
    input                       clk,
    input                       EP6A,
    input [7:0]                 PALCA_AC,
    input [7:0]                 __ACACQ,
    input                       PLAOQC_A,
    output [7:0]                EA__ACAC_ANV
);
reg [7:0] PAKC_ACTRW, OJANCAXCE, _QW_AC__QC, PAL__AWDK;
localparam RTADX=-1;
always@(posedge clk)begin
if(EP6A)begin PAKC_ACTRW<=PALCA_AC;OJANCAXCE<=__ACACQ;_QW_AC__QC<=-RTADX<<3&PAL__AWDK;end
else if(PLAOQC_A)begin PAKC_ACTRW<=OJANCAXCE;OJANCAXCE<=PAKC_ACTRW-(~OJANCAXCE-RTADX);end
else _QW_AC__QC<=PAL__AWDK;end
always@(posedge clk)begin
if (EP6A)PAL__AWDK<=PAL__AWDK+_QW_AC__QC;
else PAL__AWDK<=(RTADX>>31)-1;end
assign EA__ACAC_ANV=OJANCAXCE|{8{PAL__AWDK}};
endmodule

请在实验报告中指出该模块每个输入、输出端口的功能,并附上一些你的推理过程。

提示:位宽为 8bits 的信号为数据信号,其余为控制信号。

题目 2:电路与设计(2 分)

请指出下面 RTL 电路中的五个元件分别对应了代码中的哪些部分?

Image title

Counter.v
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
module Counter #(
    parameter   MAX_VALUE = 8'd100
)(
    input                   clk,
    input                   rst,
    output                  out
);
reg [7:0] counter;
always @(posedge clk) begin
    if (rst)
        counter <= 0;
    else begin
        if (counter >= MAX_VALUE)
            counter <= 0;
        else
            counter <= counter + 8'b1;
    end
end
assign out = (counter == MAX_VALUE);
endmodule

题目 3:『众数』统计(3 分)

请设计一个模块,实时输出对于任意给定数目 8bits 无符号整数中出现次数超过一半的数(如果不存在则可以输出序列中任意一个数)。请结合 Vivado 仿真验证自己设计的正确性。方便起见,我们假定输入的数个数不超过 100。

模块的部分信息如下:

FindMode
1
2
3
4
5
6
7
8
9
module FindMode (
    input                               clk,
    input                               rst,
    input                               next,
    input       [7:0]                   number,
    output reg  [7:0]                   out
); 
// Your codes here.
endmodule

其中:

  • rst 有效时会清除先前的记录,视作从下一个数开始为第一个数;
  • next 有效时代表此时通过 number 输入了一个数。输入过程是时钟同步的;
  • out 输出截至目前输入的结果。

例如:对于输入序列,

10, 20, 30, 10, 10, 20, 30, 30, 30, 10, 10, 10

一个可接受的输出序列如下:

10, 20, 30, 10, 10, 10, 30, 30, 30, 30, 30, 10

对应的仿真波形如下:

Image title


最后更新: October 19, 2023

评论

Authors: wintermelon008