- 四位加法器的实现(全加器和半加器)
- 半加器(Half Adder)
半加器是数字电路中用于两个单个位二进制数相加的电路,产生一个和位(sum)和一个进位位(carry)。
半加器Verilog代码
verilog
module half_adder (
input wire a, // 输入位 a
input wire b, // 输入位 b
output wire sum, // 和
output wire carry // 进位
);
assign sum = a ^ b; // 异或操作生成和
assign carry = a & b; // 与操作生成进位
endmodule
二、全加器(Full Adder)
全加器是数字电路中用于三个单个位二进制数相加的电路,产生一个和位(sum)和一个进位位(carry)。
全加器Verilog代码
verilog
复制代码
module full_adder (
input wire a, // 输入位 a
input wire b, // 输入位 b
input wire cin, // 输入进位
output wire sum, // 和
output wire carry // 进位
);
assign sum = a ^ b ^ cin; // 异或操作生成和
assign carry = (a & b) | (b & cin) | (a & cin); // 与和或操作生成进位
endmodule
三、四位全加器(4-bit Ripple Carry Adder)
四位全加器是由多个全加器串联组成的,用于对两个四位二进制数进行相加。
四位全加器Verilog代码
verilog
module four_bit_adder (
input wire [3:0] a, // 4位输入 a
input wire [3:0] b, // 4位输入 b
input wire cin, // 输入进位
output wire [3:0] sum, // 4位和
output wire carry // 输出进位
);
wire c1, c2, c3; // 内部进位信号
// 实例化全加器模块
full_adder fa0 (
.a(a[0]),
.b(b[0]),
.cin(cin),
.sum(sum[0]),
.carry(c1)
);
full_adder fa1 (
.a(a[1]),
.b(b[1]),
.cin(c1),
.sum(sum[1]),
.carry(c2)
);
full_adder fa2 (
.a(a[2]),
.b(b[2]),
.cin(c2),
.sum(sum[2]),
.carry(c3)
);
full_adder fa3 (
.a(a[3]),
.b(b[3]),
.cin(c3),
.sum(sum[3]),
.carry(carry)
);
endmodule
代码解释
半加器:
输入:a 和 b
输出:sum(和)和 carry(进位)
异或操作 (^) 用于生成和,& 操作用于生成进位。
全加器:
输入:a、b 和 cin(输入进位)
输出:sum(和)和 carry(进位)
异或操作 (^) 用于生成和,组合的与和或操作 (& 和 |) 用于生成进位。
四位全加器:
输入:两个四位二进制数 a 和 b,以及一个输入进位 cin
输出:四位和 sum 和输出进位 carry
使用4个全加器模块实例化,实现串联进位逻辑。
内部进位信号 c1、c2 和 c3 用于连接各个位的进位。
- Verilog编程实现奇数分频器和偶数分频器
- 奇数分频器
奇数分频器的实现通常需要使用计数器和触发器来生成所需的分频信号。假设我们需要实现一个3分频器,即将输入时钟频率除以3。
module odd_divider (
input wire clk_in, // 输入时钟
input wire rst_n, // 复位信号,低电平有效
output reg clk_out // 输出时钟
);
reg [1:0] counter; // 2位计数器
always @(posedge clk_in or negedge rst_n) begin
if (!rst_n)
counter <= 2'b0;
else
counter <= counter + 1'b1;
end
always @(posedge clk_in or negedge rst_n) begin
if (!rst_n)
clk_out <= 1'b0;
else if (counter == 2'b10) // 当计数器值为2时,翻转输出时钟
clk_out <= ~clk_out;
end
endmodule
- 偶数分频器
偶数分频器的实现相对简单,可以通过一个计数器和简单的逻辑操作来实现。假设我们需要实现一个4分频器,即将输入时钟频率除以4。
module even_divider (
input wire clk_in, // 输入时钟
input wire rst_n, // 复位信号,低电平有效
output reg clk_out // 输出时钟
);
reg [1:0] counter; // 2位计数器
always @(posedge clk_in or negedge rst_n) begin
if (!rst_n)
counter <= 2'b0;
else if (counter == 2'b11) // 当计数器值为3时,复位计数器
counter <= 2'b0;
else
counter <= counter + 1'b1;
end
always @(posedge clk_in or negedge rst_n) begin
if (!rst_n)
clk_out <= 1'b0;
else if (counter == 2'b11) // 当计数器值为3时,翻转输出时钟
clk_out <= ~clk_out;
end
endmodule
代码解释
奇数分频器(3分频器):
输入信号:
clk_in:输入时钟信号
rst_n:复位信号,低电平有效
输出信号:
clk_out:输出分频时钟信号
实现原理:
使用一个2位计数器对输入时钟进行计数。
当计数器值达到2时,翻转输出时钟信号,并继续计数。
偶数分频器(4分频器):
输入信号:
clk_in:输入时钟信号
rst_n:复位信号,低电平有效
输出信号:
clk_out:输出分频时钟信号
实现原理:
使用一个2位计数器对输入时钟进行计数。
当计数器值达到3时,翻转输出时钟信号,并将计数器复位。
设计注意事项
复位信号:复位信号用于初始化计数器和输出时钟信号。在设计中,复位信号通常是低电平有效(Active Low)。
计数器位数:计数器的位数应根据分频系数确定。例如,3分频和4分频都可以使用2位计数器。如果分频系数更大,则需要更多位的计数器。
仿真验证:在综合和下载到硬件之前,建议使用仿真工具(如ModelSim)对分频器进行功能验证,确保设计的正确性。
- 移位寄存器
串行输入/串行输出(SISO)移位寄存器
module siso_shift_register (
input wire clk, // 时钟信号
input wire rst_n, // 复位信号,低电平有效
input wire s_in, // 串行输入数据
output reg s_out // 串行输出数据
);
reg [3:0] shift_reg; // 4位移位寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
shift_reg <= 4'b0;
s_out <= 1'b0;
end else begin
shift_reg <= {shift_reg[2:0], s_in}; // 数据左移,s_in进入最低位
s_out <= shift_reg[3]; // 最高位输出
end
end
endmodule
串行输入/并行输出(SIPO)移位寄存器
module sipo_shift_register (
input wire clk, // 时钟信号
input wire rst_n, // 复位信号,低电平有效
input wire s_in, // 串行输入数据
output reg [3:0] p_out // 并行输出数据
);
reg [3:0] shift_reg; // 4位移位寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
shift_reg <= 4'b0;
else
shift_reg <= {shift_reg[2:0], s_in}; // 数据左移,s_in进入最低位
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
p_out <= 4'b0;
else
p_out <= shift_reg; // 并行输出
end
endmodule
并行输入/串行输出(PISO)移位寄存器
module piso_shift_register (
input wire clk, // 时钟信号
input wire rst_n, // 复位信号,低电平有效
input wire load, // 加载使能信号
input wire [3:0] p_in, // 并行输入数据
output reg s_out // 串行输出数据
);
reg [3:0] shift_reg; // 4位移位寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
shift_reg <= 4'b0;
else if (load)
shift_reg <= p_in; // 并行加载数据
else
shift_reg <= shift_reg >> 1; // 数据右移
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
s_out <= 1'b0;
else
s_out <= shift_reg[0]; // 最低位输出
end
endmodule
并行输入/并行输出(PIPO)移位寄存器
module pipo_shift_register (
input wire clk, // 时钟信号
input wire rst_n, // 复位信号,低电平有效
input wire load, // 加载使能信号
input wire [3:0] p_in, // 并行输入数据
output reg [3:0] p_out // 并行输出数据
);
reg [3:0] shift_reg; // 4位移位寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
shift_reg <= 4'b0;
else if (load)
shift_reg <= p_in; // 并行加载数据
else
shift_reg <= shift_reg; // 保持当前数据
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
p_out <= 4'b0;
else
p_out <= shift_reg; // 并行输出
end
endmodule
- meanly型和moore型状态机
在 Moore 型状态机中,输出仅依赖于当前状态,因此状态转换需要考虑输入信号,并且状态机的输出在状态转换完成后更新。
module moore_fsm_11 (
input wire clk, // 时钟信号
input wire rst_n, // 复位信号,低电平有效
input wire din, // 数据输入
output reg dout // 数据输出
);
typedef enum reg [1:0] {IDLE, S1, S2} state_t;
state_t state, next_state;
// 状态转移
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= IDLE;
else
state <= next_state;
end
// 下一状态逻辑
always @(*) begin
case (state)
IDLE: next_state = din ? S1 : IDLE;
S1: next_state = din ? S2 : IDLE;
S2: next_state = din ? S2 : IDLE;
default: next_state = IDLE;
endcase
end
// 输出逻辑
always @(state) be
在 Mealy 型状态机中,输出依赖于当前状态和当前输入,因此状态转换和输出生成可以在同一时钟周期内完成
module mealy_fsm_11 (
input wire clk, // 时钟信号
input wire rst_n, // 复位信号,低电平有效
input wire din, // 数据输入
output reg dout // 数据输出
);
typedef enum reg [1:0] {IDLE, S1} state_t;
state_t state, next_state;
// 状态转移
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= IDLE;
else
state <= next_state;
end
// 下一状态逻辑
always @(*) begin
case (state)
IDLE: next_state = din ? S1 : IDLE;
S1: next_state = din ? S1 : IDLE;
default: next_state = IDLE;
endcase
end
// 输出逻辑
always @(*) begin
case (state)
IDLE: dout = 1'b0;
S1: dout = din ? 1'b1 : 1'b0;
default: dout = 1'b0;
endcase
end
endmodule
Moore 型状态机:
输出仅依赖于当前状态,通常在状态转换完成后更新输出。
状态机实现相对简单,但有一个时钟周期的延迟。
Mealy 型状态机:
输出依赖于当前状态和当前输入,能够更快响应输入变化。
状态机实现稍复杂,但没有额外的时钟周期延迟。
Moore 型状态机
状态定义:
IDLE: 初始状态,没有检测到“1”。
S1: 检测到一个“1”。
S2: 检测到两个连续的“1”,输出为“1”。
状态转移:
在 IDLE 状态,如果输入 din 为“1”,则转移到 S1 状态,否则保持在 IDLE 状态。
在 S1 状态,如果输入 din 为“1”,则转移到 S2 状态,否则返回 IDLE 状态。
在 S2 状态,如果输入 din 为“1”,则保持在 S2 状态,否则返回 IDLE 状态。
输出逻辑:
输出 dout 在 S2 状态时为“1”,在其他状态时为“0”。
Mealy 型状态机
状态定义:
IDLE: 初始状态,没有检测到“1”。
S1: 检测到一个“1”。
状态转移:
在 IDLE 状态,如果输入 din 为“1”,则转移到 S1 状态,否则保持在 IDLE 状态。
在 S1 状态,如果输入 din 为“1”,则保持在 S1 状态,否则返回 IDLE 状态。
输出逻辑:
在 S1 状态时,如果输入 din 为“1”,则输出 dout 为“1”,否则为“0”。
在 IDLE 状态时,输出 dout 为“0
- 按键消抖以及毛刺的解决
利用Verilog实现按键的消抖;同时写出解决毛刺的方法,并举例说明。
按键消抖可以通过对按键信号进行采样和滤波来实现。常见的方法是使用计数器对稳定的按键状态进行确认。
module debounce (
input wire clk, // 时钟信号
input wire rst_n, // 复位信号,低电平有效
input wire button_in, // 按键输入
output reg button_out // 消抖后的按键输出
);
reg [15:0] counter; // 16位计数器
reg button_sync_0, button_sync_1; // 同步寄存器
// 按键输入信号同步到时钟域
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
button_sync_0 <= 0;
button_sync_1 <= 0;
end else begin
button_sync_0 <= button_in;
button_sync_1 <= button_sync_0;
end
end
// 按键消抖逻辑
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
counter <= 0;
button_out <= 0;
end else if (button_sync_1 == button_out) begin
counter <= 0;
end else begin
counter <= counter + 1;
if (counter == 16'hFFFF) begin
counter <= 0;
button_out <= button_sync_1;
end
end
end
endmodule
毛刺问题可以通过滤波器或锁存器来解决,这里我们采用锁存器的方法。在毛刺出现时锁存器能保持前一个稳定的状态,从而过滤掉毛刺信号。
module glitch_filter (
input wire clk, // 时钟信号
input wire rst_n, // 复位信号,低电平有效
input wire signal_in, // 输入信号
output reg signal_out // 过滤毛刺后的输出信号
);
reg signal_sync_0, signal_sync_1; // 同步寄存器
// 输入信号同步到时钟域
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
signal_sync_0 <= 0;
signal_sync_1 <= 0;
end else begin
signal_sync_0 <= signal_in;
signal_sync_1 <= signal_sync_0;
end
end
// 锁存器实现毛刺过滤
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
signal_out <= 0;
else if (signal_sync_1 == signal_out)
signal_out <= signal_out;
else
signal_out <= signal_sync_1;
end
endmodule