状态机思想编程
用状态机思想重新写一个 LED流水灯的FPGA代码,并写出仿真测试代码
LED_Shifter
module LED_Shifter(
input clk, // 时钟信号
input rst_n // 异步复位信号
output reg [3:0] led // 4位LED输出
);
reg [23:0] counter; // 24位计数器
// 状态更新逻辑
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
led <= 4'b0000;
counter <= 24'd0;
end else begin
counter <= counter + 1;
if (counter == 24'd4999999) begin
counter <= 24'd0;
led <= {led[2:0], led[3]};
end
end
endmodule
LED_Shifter——tb.v
`timescale 1ns / 1ps
module LED_Shifter_tb;
reg clk;
reg rst_n;
wire [3:0] led;
// 实例化待测试模块
LED_Shifter uut (
.clk(clk),
.rst_n(rst_n),
.led(led)
);
// 生成时钟信号
initial begin
clk = 0;
forever #10 clk = ~clk; // 产生50MHz时钟
end
// 初始化块
initial begin
// 初始化输入
rst_n = 0;
led = 0;
// 异步复位
#100;
rst_n = 1;
#100;
rst_n = 0;
end
// 测试过程
initial begin
// 等待复位结束
#1000;
// 检查LED状态
#50000; // 等待一段时间观察LED变化
$finish; // 结束仿真
end
endmodule
实验结果
见视频博客
CPLD和FPGA芯片的主要技术区别是什么? 它们各适用于什么场合?
CPLD(Complex Programmable Logic Device)和FPGA(Field-Programmable Gate Array)是两种不同的可编程逻辑器件,它们在结构、适用场景、配置技术等方面有一些关键的区别。
- 结构和架构CPLD通常由逻辑阵列块(LAB)、可编程互连阵列(Interconnect)和I/O模块组成。FPGA由可编程逻辑块(CLB)、可编程片上内存(Block RAM)、可编程I/O资源和其他特定功能模块组成。FPGA提供了更大的逻辑容量和更灵活的资源分配,适用于大规模和高度并行的逻辑设计。
- 适用场景CPLD适用于中等规模、低功耗、低成本的逻辑设计,通常用于控制和接口电路、时序逻辑等应用。FPGA适用于大规模、高性能、灵活性要求高的逻辑设计,常用于数字信号处理、通信、图像处理等复杂的应用。
- 配置技术CPLD使用EEPROM、Flash等非挥发性存储器进行配置,配置速度较快,但无法实时重配置。FPGA使用SRAM(静态随机存储器)进行配置,具有动态重配置的能力,支持实时修改设计。
- 时序和时钟管理CPLD通常具有固定的时序延迟,时钟管理相对简单,适合于一些实时控制应用。FPGA时序性能高度可配置,具有更复杂的时钟管理结构,适用于高性能、高时序精度的应用。
- 成本CPLD成本相对较低,适合一些成本敏感的应用。FPGA成本较高,但提供更大规模、更高性能的逻辑容量。
- 功耗CPLD通常具有较低的功耗,适合一些对功耗敏感的应用。FPGA由于更大的逻辑容量和灵活性,通常具有较高的功耗。
综上所述,CPLD和FPGA都是灵活的可编程逻辑器件,但它们在适用场景、资源结构、配置技术等方面存在显著的差异,因此在选择时需要根据具体的应用需求和性能要求做出合适的选择。
在hdlbitsFPGA教程网站上进行学习。然后在线刷题,完成组合逻辑(combinational logic)中的各题目。
1.线零
创建一个具有一个 input 和一个 output 的模块,其行为类似于一条线。与物理电线不同,Verilog 中的电线(和其他信号)是定向的。这意味着信息仅沿一个方向流动,从 (通常一个) 源流向接收器 (源通常也称为驱动器,将值驱动到线路上) 。在 Verilog 的 “continuous assignment” () 中,右侧的信号值被驱动到左侧的导线上。赋值是 “continuous” 的,因为即使右侧的值发生变化,赋值也会一直继续。连续分配不是一次性事件。assign left_side = right_side;模块上的端口也有一个方向(通常是 input 或 output)。input port 由模块外部的物体驱动,而 output port 驱动外部的物体。从模块内部查看时,input port 是 driver 或 source,而 output port 是 sink。下图说明了 circuit 的每个部分如何对应于 Verilog 代码的每个位。module 和 port 声明创建电路的黑色部分。您的任务是通过添加要 connect to 的语句来创建连线(绿色)。开箱即用的部件不是您关心的问题,但您应该知道,您的电路是通过将来自我们的测试线束的信号连接到您的端口来测试的。
module top_module( input in, output out );
assign out = in;
endmodule
2.线4
创建一个具有 3 个输入和 4 个输出的模块,其行为类似于进行以下连接的电线:a -> w
b -> x
b -> y
c -> z下图说明了 circuit 的每个部分如何对应于 Verilog 代码的每个位。 从模块外部,有三个输入端口和四个输出端口。当您有多个 assign 语句时,它们在代码中的显示顺序无关紧要。与编程语言不同,赋值语句(“连续赋值”)描述事物之间的连接,而不是将值从一个事物复制到另一个事物的作。现在也许应该澄清一个潜在的混淆来源:这里的绿色箭头代表 电线之间的连接,但本身不是电线。该模块本身已经声明了 7 条电线(名为 a、b、c、w、x、y 和 z)。这是因为 and 声明 除非另有说明,否则实际上声明了一条线。写入与 相同。因此,这些语句不是在创建连线,而是在 已经存在的 7 根电线。
module top_module(
input a,b,c,
output w,x,y,z );
assign w = a; // 将输入a的值赋给输出w
assign x = b; // 将输入b的值赋给输出x
assign y = b; // 将输入b的值赋给输出y
assign z = c;
endmodule
3.Notgate
创建一个实现 NOT 门的模块。该电路类似于线,但略有不同。当从电线到电线进行连接时,我们将实现一个逆变器(或“NOT-gate”)而不是普通电线。inout使用 assign 语句。该语句将持续驱动 的逆 on wire 。
module top_module( input in, output out );
assign out = ~in;
endmodule
4.安德盖特
创建一个实现 AND 门的模块。此电路现在有三根线(、 和 )。Wires 和 already has values driven by the input ports.但 wire 目前不受任何因素驱动。编写一个使用信号 和 的 AND 驱动的语句。aboutaboutassignoutab请注意,此电路与NOT 门,只需多输入一个。如果听起来不同,那是因为我已经开始将信号描述为被驱动(具有由附加的某物决定的已知值)或不由某物驱动。 由模块外部的某个东西驱动。 语句将 logic level 驱动到一个 wire 上。正如你所料,一条线不能有多个 driver (如果有的话,它的 logic level 是多少?),而没有 drivers 的 wire 将有一个未定义的值(在综合硬件时通常被视为 0)。
module top_module(
input a,
input b,
output out );
assign out = a & b;
endmodule
5.诺盖特
创建一个实现 NOR 门的模块。NOR 门是输出反转的 OR 门。用 Verilog 编写 NOR 函数时需要两个运算符。语句驱动具有值的 wire(或更正式的名称为 “net”)。这个值可以是你想要的复杂函数,只要它是一个组合(即无内存、没有隐藏状态)函数。语句是一个连续的赋值,因为每当它的任何输入发生变化时,输出就会永远 “重新计算”,就像一个简单的逻辑门一样。
module top_module(
input a,
input b,
output out );
assign out = ~(a | b);
endmodule