0%

FPGA-复习资料

FPGA复习资料

本复习资料由 wykcat 总结。想要更多其它资料请前往吾猫的猫窝

在此特别感谢 CaptainLiGolden 在制作本份文档中所作出的特别贡献。

思维导图

FPGA语句_00

一、单选题(仅给出答案)

  1. 在Verilog中,哪个关键字用于定义模块的开始:module

  2. Verilog是一种用于描述数字电路的语言,它是一种:硬件描述语言/高级语言

  3. Verilog的设计单元包括:模块(记这个就行了),端口,参数,实例,连续赋值语句,过程块,任务和函数

  4. Verilog的赋值语句中,”=”表示:阻塞赋值。”<=”表示:非阻塞赋值

  5. Verilog中的always块用于:顺序执行代码块

  6. 在Verilog语言中,a = 4’b1011,那么^a = 1’b1(按位异或的计算)

  7. 一个 8位二进制加法计数器, 初始状态为 00000000, 问经过 268个输入脉冲后, 此计数器的状态为:00001100(溢出位舍去)

  8. 下列标识符中,9moon是不合法的标识符。(标识符必须以字母或下划线开头,后面可以是字母、数字或下划线的组合;标识符不能是Verilog中的关键字或保留字,如 modulealways 等)

  9. 下列语句中,不属于并行语句的是:case语句

  10. 已知 “a =1’b1; b=3’b001;”那么 {a,b} = 4‘b1001(拼接操作)

  11. 关于过程块以及过程赋值描述中,下列正确的是:在过程赋值语句中表达式左边的信号一定是寄存器类型

  12. Verilog 语言与 语言的区别,不正确的描述是:Verilog 语言源于 C 语言,包括它的逻辑和延迟。

  13. 下列模块的例化正确的是: Mydesign design(.sin(sin), .sout(sout))

  14. 下列 Verilog HL语言中寄存器类型数据定义与注释矛盾的是: reg {1:5} dig //dig 为 4 位寄存器

  15. 下列关于非阻塞赋值运算方式(如 b<=a)说法错误的是: b 的值在赋值语句执行完后立刻就改变的。

  16. 下列关于阻塞赋值运算方式(如 b=a)说法错误的是:在“always”模块中的 reg 型信号都采用此赋值方式

  17. assign s= (a >=2 ) ? 1 : (a < 0) ? 2: 0 :a=2(题库是这么判的,但显然题不全 o.O)

  18. 在 Verilog HDL 语言中的位拼接运算符是:{ }

  19. Verilog中用于表示逻辑非的关键字是:!

  20. Verilog中,用于声明输入端口的关键字是:input

  21. 在Verilog中,哪个操作符用于表示逻辑与:&&

  22. 哪个关键字用于在Verilog中声明一个寄存器类型的变量: reg

  23. 在Verilog中,哪个语句用于描述顺序执行的操作: begin-end

  24. Verilog中,哪个语句用于条件判断:if-else

  25. Verilog中用于描述组合逻辑的关键字是:assign

  26. Verilog中,哪个关键字用于定义模块的结束: endmodule

  27. Verilog中,哪个关键字用于定义任务: task

  28. Verilog中,哪个关键字用于定义时间延迟: #

  29. 在Verilog HDL的逻拇运算中,设=8’b11010001,=8’b00011001,则表达式”&”的结果为:8’b00010001

  30. 已知=3’b110,=3’b000,则||结果为:1

  31. Verilog HL定义了一系列保留字,叫做关键词,指出下列哪一个不属于关键词:Wire

  32. 没有声明位宽的wire类型默认是 1 位。

  33. 由于线网类型代表的是物理连接线,因此它不存贮逻辑值,必须由器件所驱动。当一个wire类型的信号没有被驱动时,缺省值为 Z

  34. 信号没有定义数据类型时,缺省为 wire 类型。

  35. 寄存器类型在赋新值以前保持原值

  36. 输出端口可以由net/register驱动,但输入端口只能是 net 类型。

  37. reg类型的数组通常用于描述存储器,reg[15:0]MEM[0:1023];定义存储器字的位宽为:16

  38. 下列关于同步有限状态机的描述错误的是:状态是否变化要根据输入信号,只要输入条件满足,就会立刻转入到下一 个状态

  39. 下列关于流水线的描述错误的是:增加流水线长度可以节省更多延迟,流水线越长,首次延迟越大,系统频 率就会降低

  40. 以下关于Top-own的设计方法不正确的描述是: Top-Down设计中的系统总体仿真与所选工艺有关

  41. always begin 5 clk=0;10 clk=~clk; end产生的波形:占空比1/3

  42. 时间尺度定义为`timescale 10ns/100ps,时间精度100ps

  43. 可综合代码中下列说法正确的是: 不能出现“# d”延时控制语句

  44. 下列语句中,不属于并行语句的是:case语句

  45. Verilog中,用于声明常量的关键字是: parameter

  46. 在Verilog中,哪个符号用于注释单行: //

  47. Verilog中,哪个操作符用于按位与运算:&

  48. Verilog中用于声明整数的关键字是: integer

  49. Verilog中,哪个操作符用于逻辑或运算: ||

  50. 在Verilog的always块中,哪个关键字用于定义时钟的上升边沿触发: posedge

  51. 在Verilog中,哪个符号用于表示按位或操作:|

  52. Verilog中,哪个关键字用于定义无限循环: forever

  53. Verilog中,哪个操作符用于按位异或运算:^

  54. 在Verilog的函数定义中,哪个关键字用于返回函数的值: return

  55. Verilog中的数据类型wire和reg的区别在于: wire用于内部信号连接,reg用于存储数据

  56. 如下程序代码,200ns后,信号q1的值为8’d10

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    `timescale 10ns/1ns
    module test;
    reg
    [7:0]data;
    reg clk;
    initial
    begin
    clk = 0;
    #10 data = 8’d10;
    #20 data = 8’h15;
    #40 data = 8’h25;
    end
    always #5 clk = ~clk;
    reg [7:0] q1,q2,q3;
    always @ (posedge clk)
    begin
    q2 = q1;
    q1 = data;
    q3 = q2;
    end
    endmodule
  57. 在Verilog中,哪个关键字用于定义在仿真过程中值可以改变的变量:reg

  58. 在Verilog中,always块的触发条件是什么:可以由信号的任何变化触发

  59. 在Verilog中,以下哪个选项正确地实现了一个2输入N门的行为: assign Y = A & B

  60. 在Verilog中,向量的位宽和方向如何定义:{高位:低位}名称

  61. 在Verilog中,哪个关键字用于创建只在指定条件下激活的过程块:always。

  62. 以下哪个选项是Verilog中合法的向量声明:wire [3:0] vect

  63. 在Verilog中,initial块是如何执行的: 仅在仿真开始时执行一次

  64. 在Verilog中,$finish是用来做什么的:结束仿真

  65. 哪个关键字用于在Verilog中定义一个时序逻辑块: always @(posedge clock)

  66. Verilog中的三态缓冲器是如何表示的: assign Y = enable ? A : ‘Z’

  67. 在Verilog中,哪个关键字表示敏感列表中的任意变化:*

  68. 哪种类型的赋值在Verilog中用于组合逻辑: Blocking

  69. 在Verilog中,哪个关键字用于指定模块的输出: output

  70. Verilog中的模块实例化和连接正确的方式是什么: 模块名 实例名(端口连接)

  71. 在Verilog中,如何注释一段代码: // This is a comment /* This is a comment */

  72. Verilog中的$monitor语句是用来做什么的: 监控变量的变化并打印

  73. 在Verilog中定义一个名为“counter”的模块,其端口列表中没有端口的语法是:module counter()

  74. 在Verilog中,连续赋值语句是什么:assign

  75. 在Verilog中,如何声明一个带有8位宽并初始值为0的寄存器变量: reg [7:0] var = 0

  76. 在Verilog中定义一个参数化模块时使用的关键字是什么: parameter

  77. 如何在Verilog中表示十六进制数5: 8’h5

  78. 在Verilog中,正确的方式来声明一个具有3个输入和1个输出的异或门是什么: xor (output, input1, input2, input3)

  79. 在Verilog中,哪个语句用于条件编译:`ifdef

  80. 在Verilog中,如何正确初始化一个具有4个元素的整数数组: integer array[0:3] = {0, 1, 2, 3}

  81. 哪个Verilog构造用于描述硬件的物理布局: primitive

  82. 在Verilog中,一个模块可以如何引用另一个模块: 通过实例化

  83. Verilog中的$time系统函数是用来做什么的:返回仿真的当前时间

  84. 哪个Verilog操作符用于位宽减少的逻辑或:|

  85. 在Verilog中,如何表示一个模块的端口既可以是输入也可以是输出: inout

  86. 哪个关键字在Verilog中用于指示一个块仅在仿真开始时执行一次:initial

  87. 在Verilog中,哪个关键字用来描述一个可以在仿真期间多次执行的代码块: always

  88. 哪个Verilog构造用于基于表达式的值选择一个执行语句:case

  89. Verilog中的模块参数化(parameterization)允许做什么:使模块能够接受在实例化时设置的值

  90. 在Verilog中使用$stop和$finish有什么区别:$stop暂停仿真,$finish终止仿真

  91. Verilog的generate语句用于什么: 根据条件生成代码

  92. 如何在Verilog中声明一个内部使用的局部参数:localparam

  93. 在Verilog中,用于描述一个模块能够处理的信号边缘类型(如上升沿或下降沿)的关键字是: posedge / negedge

  94. 如何在Verilog中声明一个模拟时钟信号: always #10 clk = !clk

  95. 在Verilog中,具有默认值的case语句应该使用哪个关键字:default

  96. Verilog中的“task”和“function”有何不同: task可以有多个输出,而function只能有返回值

  97. FPGA 是指什么: Field Programmable Gate Array

  98. Verilog 是一种什么类型的语言: 高级硬件描述语言

  99. Verilog 中的非阻塞赋值(<=)和阻塞赋值(=)的区别是什么:非阻塞赋值可以并行执行,阻塞赋值按顺序执行

  100. FPG 中的时钟资源通常由什么提供:振荡器

  101. Verilog 中的 always @(A or B) 表示什么意思:当 A 或 B 的值发生变化时触发

  102. FPGA 的配置信息通常存储在一种叫做Flash的非易失性存储器中。

  103. 块语句中,一种是begin-end语句,通常用来标志顺序执行的语句;一种是 fork_join语句,通常用来标志并行执行的语句,在描述需要使用FPG实现的逻辑功能时,两种语句: 均可使用

  104. FPGA中的逻辑单元(Logic Element,LE)主要用于实现哪种功能: 逻辑运算

  105. FPGA与传统微处理器(如CPU)相比,主要的优势是什么: 可编程性和灵活性

  106. 在FPGA设计中,使用哪种文件来描述硬件逻辑:HDL(硬件描述语言)文件

  107. FPGA编程后,其内部结构是如何连接的: 通过可配置的逻辑块和可编程互连。

  108. 哪个公司是FPGA技术的主要供应商之一: Intel

  109. FPGA中的查找表(LUT)用于实现什么:逻辑函数

  110. 为了在FPGA上实现一个新的设计,工程师通常使用什么过程: 综合

  111. FPGA中的配置数据通常存储在哪里: FLASH

  112. FPGA的哪个特性使其非常适合用于并行处理任务:大量的逻辑单元

  113. FPGA上的程序是如何加载的:在开机时通过外部设备加载

  114. 如下程序代码,200ns后,信号q1的值为8’d10

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    `timescale 10ns/1ns
    module test;
    reg [7:0] data;
    reg clk;
    initial
    begin
    clk = 0;
    #10 data = 8’d10;
    #20 data = 8’h15;
    #40 data = 8’h25;
    end
    always #5 clk = ~clk;
    reg [7:0] q1,q2,q3;
    always @ (posedge clk)
    begin
    q2 = q1;
    q1 = data;
    q3 = q2;
    end
    endmodule

二、简答题

  1. 列举并解释Verilog HDL中常用的几种数据类型,如wire、reg、integer等。并说明它们在设计中的不同应用场景。
    答:
    ①wire:线网型,通常用于连接模块之间的信号线,传递数据和控制信号,不存储状态,在组合逻辑中使用。
    ②reg:寄存器型,可以存储状态或数据,用于时序逻辑。
    ③Integer:32位带符号整数,通常用于表示计数器。
    ④parameter:通常用于定义常量。

  2. 简述Verilog HDL设计的层次结构,并解释module、端口和实例化的作用。
    答:自顶向下的设计,层次结构包括顶层模块、子模块和实例化模块三个层次;module用于定义模块,可以包含输入端口、输出端口、内部信号和功能实现;端口是模块与外部环境之间的接口,用于输入和输出数据。通过实例化子模块,并通过端口连接来构建整个设计,实现了设计的层次结构和模块化设计。

  3. 什么是Verilog中的always块?请给出一个例子说明。
    答:always块是一种用于描述在特定条件下执行的行为的结构。它可以在特定的事件或条件发生时触发,并且可以用于实现组合逻辑always @(*)和时序逻辑always @(posedge clk or posedge rst)。

  4. forever块和always块的区别是什么?
    答:always块用于需要根据特定条件触发执行的情况,而forever块为无限循环执行的情况。

  5. Verilog 中的参数和宏的共同点和区别是什么?
    答:共同:都可以定义常量。区别:作用域不同,参数是模块级别,宏是文件级别;参数一旦定义后就不能更改,宏可以在定义后被重新定义或取消定义;参数可以是任何数据类型,宏通常用于定义简单的文本替换。

  6. Verilog语法中举例表述任务与函数,并说明有何区别?
    答:
    任务:可以支持多种目的,能计算多个结果值,这些结果值只能通过被调用的任务的输出或总线端口输出。能够启动其他任务或函数。可以没有或有多个任何类型的变量。没有返回值。

    1
    2
    3
    4
    5
    6
    7
    task <任务名>;
    <端口及数据类声明语句>
    begin
    <语句1>
    end
    endtask
    例:neg_clocks(3)

    函数:通过返回一个值来响应输入信号的值,一般将函数作为表达式中的操作符,这个操作的结果值就是这个函数的返回值。不能启动任务。需要至少一个输入变量。有一个返回值。函数的仿真时间为零。函数的调用不能单独作为一条语句出现。函数定义结构中不允许出现任何的输出端口(output)和输入/输出端口(inout)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function<返回值类型或返回值宽度> <函数名>;
    <输入端口说明>
    <局部变量说明>
    begin
    <行为语句1; >
    <行为语句2; >
    …….
    end
    endfunction
    例:out=getbyte(input1,number); assign net1=getbyte ( input1, 3 );
  7. 列举在测试模块中常用的不可综合的命令和对应的功能。
    答:
    $display:功能:在仿真过程中输出消息到仿真器的控制台。
    $monitor:功能:监视一个变量的值,并在该变量的值发生变化时输出消息到控制台。
    $stop:功能:停止仿真过程。
    $finish:功能:完成仿真过程,结束仿真。
    $random:功能:生成一个随机数。
    $time:功能:获取当前仿真时间。

  8. Testbench中的时间控制语句有哪些?它们在testbench中的主要作用是什么?请至少列举并解释3种时间控制语句的用法。
    答:
    # 指令在仿真过程中添加时间延迟。 #10; // 延时10个时间单位
    @ 指令用于等待指定的事件发生。 @(posedge clk); // 等待时钟的上升沿
    wait 指令用于等待条件满足或事件发生。 wait (rst_n == 0); // 等待复位信号为低电平

  9. 如何在testbench中产生随机的输入测试向量?
    答:使用系统函数 $random。

  10. 什么是组合电路的不完全描述?
    答:组合电路的不完全描述,通常来源于利用Verilog进行逻辑实现时没有给出选择分支的全部映射关系。设计者在代码描述中只给出了部分选择分支所对应的操作,但没有个给出完整的分支映射,在模块综合的时候,有可能生成设计者所不希望的电路结构。

  11. Verilog中如何避免组合逻辑电路的不完全描述?
    答:包括覆盖所有可能的输入情况,使用完整的 case - default 语句,在 if-else 结构中考虑所有可能的情况,初始化输出信号,使用综合工具等。

  12. 简要说明阻塞赋值和非阻塞赋值在写法上和原理上的不同。
    答:阻塞赋值=,顺序执行,在该语句结束时立刻完成赋值操作,完成该赋值语句后才能执行下一句的操作,常用于描述组合逻辑电路。
    非阻塞赋值<=,并行执行,块内的多条赋值语句在块结束时同时赋值,常用于描述时序逻辑电路。

  13. 简述同步时序电路和异步时序电路的区别。
    答:同步时序电路:同步时序电路各个触发器共用一个时钟信号,需要更新状态的触发器在时钟边沿同时翻转。
    异步时序电路:异步时序电路各个触发器状态的变化不是同步发生的,每一个触发器都有可能有自己单独的触发时钟,异步电路状态的更新没有全局的共用时钟信号。

  14. 有限状态机分为哪两类?这两类的有什么区别?
    答:Moore摩尔型状态机(Moore Machine)和Mealy米勒型状态机(Mealy Machine)。
    区别:Moore型状态机输出仅依赖于当前状态,不依赖输入信号;Mealy状态机的输出依赖于当前状态和当前输入信号。

  15. 简叙三段式状态机的写法。
    答:三个部分分别是:状态记忆、逻辑转移和逻辑输出。
    状态记忆:储存当前的逻辑状态。
    逻辑转移:负责状态机逻辑状态转移,是组合电路。其输入包含当前状态和外部输入信号。
    逻辑输出:负责逻辑输出的电路部分,摩尔机仅仅与当前状态有关,米勒机与当前状态和输入信号都有关。

  16. 简述FPGA与通用处理器和ASIC的区别。
    答:FPGA:有高度的可编程性,通过硬件描述语言编写的逻辑设计进行配置,能够并行执行多个操作,开发周期较短,灵活性高,单位成本高,适合小批量生产。
    通用处理器(GPP):具有广泛适用性,编写软件程序来执行任务,开发环境较成熟,大多数指令是逐条的,适合顺序处理任务。
    ASIC:具有专用性,可以根据需求定制化,不可重编程,高性能,低功耗,开发周期长,缺乏灵活性,单位成本低,适合大批量生产。

  17. 请简述FPGA的基本工作原理和内部硬件架构。
    答:基本工作原理:用户通过编程配置其内部的可编程逻辑资源,并根据输入信号的变化实时执行特定的功能。
    内部硬件架构:可配置逻辑块(CLB),可编程互连网络,输入输出(IOB)模块,时钟管理单元,块存储器,数字延迟锁相环(DLL)。

  18. FPGA中的时钟分频器是用来做什么的?为什么在某些设计中需要分频时钟?
    答:时钟分频器用于将输入时钟信号分频成较低频率的时钟信号。
    目的:用于降低功耗、提高可靠性、优化性能、满足接口要求以及满足时序约束。

  19. 简述FPGA实验中约束文件的作用。
    答:约束文件(Constraints File),包含了对FPGA设计的各种约束条件,包括时序约束,引脚约束,时钟约束,物理约束,确保设计在FPGA上正确运行并满足性能要求,避免时序问题和布局布线问题,提高设计的稳定性和可靠性。

  20. FPGA设计流程包括哪些主要阶段?请简要说明每个阶段的作用。
    答:需求分析:明确定义设计的功能需求、性能指标和约束条件。
    架构设计:设计FPGA系统的整体架构和模块划分。
    逻辑设计:使用硬件描述语言编写逻辑代码,实现系统功能。
    综合与优化:将逻辑设计转换为适合FPGA实现的物理电路。
    验证与仿真:进行功能验证和性能仿真。
    调试与验证:对FPGA硬件原型进行实际测试和验证。
    部署与生产:将设计部署到目标FPGA芯片并进行批量生产。

  21. 简述在FPGA设计流程中,从HDL代码到最终实现经历的主要步骤。
    答:包括HDL编写,综合布局布线,时序分析和优化,生成位流文,配置FPGA,验证和调试。

  22. 解释什么是Verilog,并简述其在电子设计自动化中的作用。
    答:Verilog HDL 是一种用于描述、设计、仿真、验证数字电子系统的硬件描述语言。
    以HDL硬件描述语言为代表的自动化设计方法在进行集成电路逻辑仿真、功能验证和布局布线等方面极大地缓解了设计师的劳动强度,从而为高复杂度芯片设计提供了可能。

  23. 描述在Verilog中,模块(module)的概念及其重要性。
    答:模块(module)是一种用于组织和抽象硬件设计的基本单元。一个模块可以包含逻辑、寄存器、子模块以及其他组件,它们一起描述了一个完整的功能单元或电路部分。
    重要性:模块化设计,可以实现层次化,提高了设计的可维护性和可扩展性,使得模块可以独立开发、测试和重用。

  24. 解释Verilog中的连续赋值(continuous assignment)语句和其用途。
    答:连续赋值是用逻辑值驱动线网,连续赋值语句assign:如,assign c = a & b,用于对wire型线网赋值。

  25. 说明如何使用Verilog进行时序控制,包括使用always块和时钟信号的示例。
    答:时序控制通常使用always块结合时钟信号来实现,用于描述在特定条件下执行的行为,如always @(posedge clk or posedge rst),表示在时钟的上升沿或复位信号触发时执行相应的操作。

  26. 什么是Verilog中的always块?请给出一个例子说明。
    答:always块是一种用于描述在特定条件下执行的行为的结构。它可以在特定的事件或条件发生时触发,并且可以用于实现组合逻辑always @(*)和时序逻辑always @(posedge clk or posedge rst)。

三、代码题

  1. 设计一个Verilog模块,实现对输入信号的去抖动处理。模块应当在输入信号稳定一定时间后才将其视为有效信号。对于输入信号IN及时钟信号 clk,输入信号为机械按键输入,抖动时间5ms到10ms,时钟频率为50MHz,要求输出1位去抖信号OUT。

    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
    module debounce (
    input wire clk, // 时钟信号
    input wire IN, // 输入信号
    output reg OUT // 去抖信号
    );

    parameter DEBOUNCE_TIME = 500000; // 抖动时间(10ms的时钟周期数)
    reg [31:0] debounce_counter; // 去抖计数器

    always @(posedge clk) begin
    // 如果输入信号发生变化
    if (IN != OUT) begin
    debounce_counter <= debounce_counter + 1;
    // 如果去抖计数器计数达到设定的抖动时间
    if (debounce_counter >= DEBOUNCE_TIME) begin
    // 将输入信号的值赋给去抖信号
    OUT <= IN;
    // 复位去抖计数器
    debounce_counter <= 0;
    end
    end else begin
    // 如果输入信号保持稳定,复位去抖计数器
    debounce_counter <= 0;
    end
    end

    endmodule
  2. 输入复位高有效信号sys_rst、时钟信号sys_clk、进位输入信号cin、两个一位的加数a、b,输出一位的和sum以及进位输出信号cout。给出各信号的真值表:
    img

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    module one_bit_adder_with_reset (
    input wire sys_rst, // 复位信号(高有效)
    input wire sys_clk, // 时钟信号
    input wire cin, // 进位输入信号
    input wire a, // 第一个加数
    input wire b, // 第二个加数
    output reg sum, // 和
    output reg cout // 进位输出信号
    );

    // 在时钟上升沿处检测复位信号
    always @(posedge sys_clk or posedge sys_rst) begin
    if (sys_rst) begin
    // 在复位信号为高时,重置sum和cout
    sum <= 1'b0;
    cout <= 1'b0;
    end else begin
    // 正常工作状态,计算和与进位
    sum <= a ^ b ^ cin;
    cout <= (a & b) | (b & cin) | (cin & a);
    end
    end

    endmodule
  3. 输入复位高有效信号sys_rst、时钟信号sys_clk、进位输入信号cin、两个两位的加数a、b,输出两位的和sum以及进位输出信号cout。要求例化两个一位加法器来实现多位加法器的功能。

    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
    32
    33
    34
    35
    36
    37
    38
    module two_bit_adder_with_reset (
    input wire sys_rst, // 复位信号(高有效)
    input wire sys_clk, // 时钟信号
    input wire cin, // 进位输入信号
    input wire [1:0] a, // 第一个两位加数
    input wire [1:0] b, // 第二个两位加数
    output reg [1:0] sum, // 两位的和
    output wire cout // 进位输出信号
    );

    wire c1; // 第一位的进位
    wire c2; // 第二位的进位

    // 实例化两个一位加法器
    one_bit_adder_with_reset adder0(
    .sys_rst(sys_rst),
    .sys_clk(sys_clk),
    .cin(cin),
    .a(a[0]),
    .b(b[0]),
    .sum(sum[0]),
    .cout(c1)
    );

    one_bit_adder_with_reset adder1(
    .sys_rst(sys_rst),
    .sys_clk(sys_clk),
    .cin(c1),
    .a(a[1]),
    .b(b[1]),
    .sum(sum[1]),
    .cout(c2)
    );

    // 进位输出为最高位的进位
    assign cout = c2;

    endmodule
  4. 实现一个模块,将3位二进制数a转换为对应的3位格雷码b。格雷码与二进制码转换表如下:
    img

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    module binary_to_gray (
    input [2:0] a, // 3位二进制数输入
    output reg [2:0] b // 3位格雷码输出
    );

    // 格雷码的最高位等于二进制的最高位
    assign b[2] = a[2];

    // 其余位的计算
    always @(*) begin
    b[1] = a[2] ^ a[1];
    b[0] = a[1] ^ a[0];
    end

    endmodule
  5. 比较两个4位二进制数,并输出三个标志:等于c1、大于c2、小于c3。输入信号a,b为4位有符号二进制数,输出高电平有效。

    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
    module binary_comparator (
    input [3:0] a, // 第一个4位有符号二进制数
    input [3:0] b, // 第二个4位有符号二进制数
    output reg c1, // 等于标志
    output reg c2, // 大于标志
    output reg c3 // 小于标志
    );

    always @(*) begin
    if (a == b) begin
    c1 = 1'b1; // 等于标志
    c2 = 1'b0; // 大于标志
    c3 = 1'b0; // 小于标志
    end else if (a > b) begin
    c1 = 1'b0;
    c2 = 1'b1;
    c3 = 1'b0;
    end else begin
    c1 = 1'b0;
    c2 = 1'b0;
    c3 = 1'b1;
    end
    end

    endmodule
  6. 生成一个伪随机二进制序列,序列每个时钟周期更新一次。输入时钟为clk,输出信号为8位二进制序列out。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    module lfsr_generator (
    input wire clk, // 时钟信号
    output reg [7:0] out // 8位二进制序列输出
    );

    reg [7:0] lfsr_reg; // LFSR 寄存器

    always @(posedge clk) begin
    // 计算下一个 LFSR 的值
    lfsr_reg[0] <= lfsr_reg[7] ^ lfsr_reg[3];
    lfsr_reg[1] <= lfsr_reg[0];
    lfsr_reg[2] <= lfsr_reg[1];
    lfsr_reg[3] <= lfsr_reg[2];
    lfsr_reg[4] <= lfsr_reg[3];
    lfsr_reg[5] <= lfsr_reg[4];
    lfsr_reg[6] <= lfsr_reg[5];
    lfsr_reg[7] <= lfsr_reg[6];

    // 输出当前 LFSR 的值
    out <= lfsr_reg;
    end

    endmodule
  7. 实现一个8位串行输入、并行输出的移位寄存器。输入时钟clk,每一时钟周期读取一次输入信号IN的值,将其置于八位输出信号out的最低位,前一时钟周期输出信号0到6位作为输出信号的高7位。

1
2
3
4
5
6
7
8
9
10
11
12
module shift_register (
input wire clk, // 时钟信号
input wire IN, // 串行输入信号
output reg [7:0] out // 并行输出信号
);

always @(posedge clk) begin
// 将当前输入信号放置于最低位
out <= {out[6:0], IN};
end

endmodule
  1. 创建一个Verilog模块,实现4选1多路选择器(MUX)。输入包括四个数据输入信号a、b、c、d,两个选择信号s0、s1和一个输出信号y。具体真值表如下:
    img

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    module mux_4to1 (
    input wire s0, // 选择信号 s0
    input wire s1, // 选择信号 s1
    input wire [3:0] a, // 数据输入信号 a
    input wire [3:0] b, // 数据输入信号 b
    input wire [3:0] c, // 数据输入信号 c
    input wire [3:0] d, // 数据输入信号 d
    output reg [3:0] y // 输出信号 y
    );

    always @(*) begin
    case({s1, s0})
    2'b00: y = a; // s1=0, s0=0
    2'b01: y = b; // s1=0, s0=1
    2'b10: y = c; // s1=1, s0=0
    2'b11: y = d; // s1=1, s0=1
    default: y = 4'bxxxx; // 默认情况,输出未定义
    endcase
    end

    endmodule
  2. 设计一个具有同步复位功能的T触发器。确保复位信号rst为高时,输出Q被置为0。当时钟上升沿时,如果T和Q不相同时,其输出值Q会是1。输入端T为1的时候,输出端的状态Q发生反转;输入端T为0的时候,输出端的状态Q保持不变(注:本题题目显然是有问题的,但是懒得探寻哪个Q是哪个Q了)
    img

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    module t_flip_flop_with_reset (
    input wire clk, // 时钟信号
    input wire rst, // 复位信号(高电平有效)
    input wire T, // T触发器输入信号
    output reg Q // Q输出信号
    );

    // 同步复位逻辑
    always @(posedge clk or posedge rst) begin
    if (rst) begin
    Q <= 1'b0; // 复位时输出Q置为0
    end else begin
    // T触发器逻辑
    if (T != Q) begin
    Q <= ~Q; // T和Q不相同时,输出值Q反转
    end
    end
    end

    endmodule
  3. 设计一个4位二进制上升沿触发计数器,具有异步清零功能,即在复位信号置0时,无论时钟信号为何值,输出都将清零。确保计数器在达到最大值后能够循环计数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    module counter (
    input wire clk, // 时钟信号
    input wire rst, // 异步清零信号
    output reg [3:0] count // 计数器输出
    );

    always @(posedge clk or negedge rst) begin
    if (!rst) begin
    count <= 4'b0000; // 清零
    end else begin
    if (count == 4'b1111) begin
    count <= 4'b0000; // 计数达到最大值后清零
    end else begin
    count <= count + 1; // 正常计数
    end
    end
    end

    endmodule
  4. 创建一个Verilog模块,将输入时钟信号clk_0进行四倍分频,输出较低频率的时钟信号clk_1,即clk_1输出频率应为输入时钟频率的四分之一。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    module clock_divider (
    input wire clk_0, // 输入时钟信号
    output reg clk_1 // 输出时钟信号
    );

    reg [1:0] count; // 计数器

    always @(posedge clk_0) begin
    count <= count + 1; // 每个时钟周期计数器加一
    if (count == 2'b11) begin
    count <= 2'b00; // 计数到3时归零
    clk_1 <= ~clk_1; // 输出时钟信号翻转
    end
    end

    endmodule
  5. 编写一个模块,将4位二进制输入x转换为驱动7段LED显示的信号,输出信号为高电平时,对应数码管亮起。输入信号记作x,输出信号led[0]到led[6]分别对应数码管a到g段。
    img

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    module binary_to_7seg(
    input [3:0] x,
    output reg [6:0] led
    );

    always @(*) begin
    case (x)
    4'b0000: led = 7'b0111111; // 数字0
    4'b0001: led = 7'b0000110; // 数字1
    4'b0010: led = 7'b1011011; // 数字2
    4'b0011: led = 7'b1001111; // 数字3
    4'b0100: led = 7'b1100110; // 数字4
    4'b0101: led = 7'b1101101; // 数字5
    4'b0110: led = 7'b1111101; // 数字6
    4'b0111: led = 7'b0000111; // 数字7
    4'b1000: led = 7'b1111111; // 数字8
    4'b1001: led = 7'b1101111; // 数字9
    default: led = 7'b0000000; // 显示空白
    endcase
    end

    endmodule
  6. 设计一个简单的4位ALU,支持至少四种操作:加法、减法、按位与、按位或。ALU应包括操作2位选择输入sel、两个4位操作数a、b输入和一个输出c。选择输入不同时进行不同运算操作即可,选择输入与运算操作的对应规则不做要求。默认a大于b。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    module alu(
    input [1:0] sel,
    input [3:0] a,
    input [3:0] b,
    output reg [3:0] c
    );

    always @(*) begin
    case (sel)
    2'b00: c = a + b; // 加法
    2'b01: c = a - b; // 减法
    2'b10: c = a & b; // 按位与
    2'b11: c = a | b; // 按位或
    default: c = 4'b0000; // 默认情况
    endcase
    end

    endmodule
  7. 已知模块my_module()中,有八位输入信号in[7:0],复位信号rst,以及八位输出信号out[7:0]。请编写对应的testbench文件,要求:输入信号每100ns变化一次,循环遍历所有输入情况;复位信号在仿真开始后500ns到600ns之间为高电平,其余时间为低电平。

    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
    32
    33
    34
    35
    36
    37
    `timescale 1ns / 1ps // 设置时间刻度

    module testbench;

    // 定义测试信号
    reg [7:0] in;
    reg rst;
    wire [7:0] out;

    // 实例化被测试的模块
    my_module dut(
    .in(in),
    .rst(rst),
    .out(out)
    );

    // 定义仿真时钟
    initial begin
    // 初始化输入
    in = 8'b00000000;
    rst = 0;

    // 仿真开始后的处理
    #500 rst = 1; // 将复位信号设置为高电平
    #100 rst = 0; // 恢复为低电平

    // 循环遍历所有输入情况
    repeat (256) begin
    // 在每个输入情况下仿真100ns
    #100 in = in + 1;
    end

    // 结束仿真
    $finish;
    end

    endmodule
  8. 已知模块my_module_1()与my_module_2()。对于my_module_1(),有输入信号clk与输出信号clk_0,其作用是将输入的时钟变频为所需频率的时钟;对于my_module_2(),有输入信号clk,复位信号rst(高电平有效),以及八位输出信号out[7:0]。请编写对应的testbench文件,要求:系统时钟频率为50MHz;观察在经过my_module_1()处理前后的时钟控制下的两out信号之和(记作tb_out[7:0])。

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    `timescale 1ns / 1ps // 设置时间刻度

    module testbench;

    // 定义测试信号
    reg clk;
    reg rst;
    wire [7:0] out_1, out_2;
    wire [7:0] tb_out;

    // 实例化被测试的模块
    my_module_1 dut1(
    .clk(clk),
    .clk_0(clk_0)
    );

    my_module_2 dut2(
    .clk(clk), // 使用经过变频前的时钟信号
    .rst(rst),
    .out(out_1)
    );

    my_module_2 dut3(
    .clk(clk_0), // 使用经过变频后的时钟信号
    .rst(rst),
    .out(out_2)
    );

    // 初始化时钟
    initial begin
    clk = 0;
    rst = 1; // 复位信号处于高电平状态
    #100; // 等待一段时间
    rst = 0; // 复位信号拉低,开始正常工作
    end

    // 生成时钟
    always begin
    #10 clk = ~clk; // 每10个时间单位翻转一次时钟
    end

    // 将两个输出信号相加
    assign tb_out = out_1 + out_2;

    // 结束仿真
    endmodule
  9. 有如下图所示的矩阵键盘,请填补程序中的空缺,使得key1按下时输出led[0]为高电平,key2按下时输出led[1]为高电平,以此类推。img

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    module keyboard(
    input clk,
    input rst_n,
    input [3:0]PD3_0,
    output reg [7:4]PD7_4,
    output reg [15:0]led
    );

    always@(posedge clk or posedge rst_n)begin
    if(rst_n)PD7_4 <= 4'b0001;
    else PD7_4[7:4] <= {PD7_4[6:4],PD7_4[7]};
    end
    //作答时请从此处开始
    always@(posedge clk)begin
    case({PD7_4[7:4],PD3_0[3:0]})

    //以下为补充代码
    8'b0001_1000:led <= 16'b0000_0000_0000_0001;
    8'b0010_1000:led <= 16'b0000_0000_0000_0010;
    8'b0100_1000:led <= 16'b0000_0000_0000_0100;
    8'b1000_1000:led <= 16'b0000_0000_0000_1000;

    8'b0001_0100:led <= 16'b0000_0000_0001_0000;
    8'b0010_0100:led <= 16'b0000_0000_0010_0000;
    8'b0100_0100:led <= 16'b0000_0000_0100_0000;
    8'b1000_0100:led <= 16'b0000_0000_1000_0000;

    8'b0001_0010:led <= 16'b0000_0001_0000_0000;
    8'b0010_0010:led <= 16'b0000_0010_0000_0000;
    8'b0100_0010:led <= 16'b0000_0100_0000_0000;
    8'b1000_0010:led <= 16'b0000_1000_0000_0000;

    8'b0001_0001:led <= 16'b0001_0000_0000_0000;
    8'b0010_0001:led <= 16'b0010_0000_0000_0000;
    8'b0100_0001:led <= 16'b0100_0000_0000_0000;
    8'b1000_0001:led <= 16'b1000_0000_0000_0000;
    //以上为补充代码

    default :led <= 16'b0000_0000_0000_0000;
    endcase
    end
    //作答时请在此处结束
    endmodule
  10. 请补充代码中缺失的部分,用于声控灯的控制。当有声音时,输入信号sound为高电平,否则为低电平,输入clk为50kHz时钟,输入rst为异步复位信号,高电平有效;输出信号为led,高电平时表示灯泡亮起。要求:系统初始状态灯泡不亮,直到接收到声音,灯泡亮起,持续3s;灯泡亮起时,若接收到声音,不会改变灯泡剩余点亮时间。

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    module sound_led(
    input sound,
    input clk,
    input rst,
    output reg led
    );

    reg [3:0] state;

    reg flag_3s;
    reg [31:0]cnt;

    parameter IDLE = 3'd0,
    START = 3'd1;

    parameter CLK_FRE = 50_000;

    always@(posedge clk or posedge rst)begin
    if(rst)begin
    state <= IDLE;
    end
    else begin
    case (state)
    IDLE :if(sound)state <= START;
    START :if(flag_3s)state <= IDLE;
    default : state <= IDLE;
    endcase
    end
    end

    always @(posedge clk)begin
    case (state)
    IDLE :begin
    cnt <= CLK_FRE*3;
    led <= 0;
    flag_3s <= 0;
    end
    START :begin
    // 以下为补充代码
    cnt=cnt-1;
    led <= 1;
    if(~cnt)flag_3s <= 1;
    // 以上为补充代码
    end
    default:begin
    cnt <= CLK_FRE*3;
    led <= 0;
    flag_3s <= 0;
    end
    endcase
    end

    endmodule
  11. 请为上题中的声控灯控制器编写相应的testbench文件,要求测试声控灯控制器的所有功能。

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    `timescale 1ns / 1ps

    module sound_led_tb;

    // 定义测试信号
    reg sound;
    reg clk;
    reg rst;
    wire led;

    // 实例化被测试的模块
    sound_led dut (
    .sound(sound),
    .clk(clk),
    .rst(rst),
    .led(led)
    );

    // 时钟发生器
    always begin
    #10 clk = ~clk; // 50kHz的时钟
    end

    // 产生声音信号
    initial begin

    // 正常持续3s亮起功能
    sound = 0;
    #100; // 等待一段时间
    sound = 1; // 使声音信号为高电平
    #200; // 持续一段时间
    sound = 0; // 关闭声音信号
    #4000000000; // 等待足够长的时间,确保灯泡亮起3秒以上

    // 在持续时间内声音信号高电平持续时间不重复计算
    sound = 1; // 使声音信号为高电平
    #200; // 持续一段时间
    sound = 0; // 关闭声音信号
    #1000000000; // 延时1s
    sound = 1; // 使声音信号为高电平
    #200; // 持续一段时间
    sound = 0; // 关闭声音信号

    $finish; // 结束仿真
    end

    // 复位控制
    initial begin
    rst = 1;
    #100; // 持续一段时间
    rst = 0; // 撤销复位
    end

    endmodule