/
...
/
/
八.FPGA Module编写 FP
Search
Try Notion
八.FPGA Module编写 FP
一.通用编写技巧
Always 语句的理解 always @(posedge clk or negedge rst_n) begin
系统更新时刻(Self Define Word)
将Always的条件,定义为系统更新条件
系统更新时刻(Self Define): 将系统状态变化视为一步一步的,而不考虑全部时间段,常见的为CLK上升沿,体现于Always的条件中
negedge rst_n 为非常规条件,定义为异常更新时刻,可用作某种"捕获"
过程块中的信号一致性
🖼️Always语句仿真图
在时钟的上升沿或复位下降沿发生变化(系统更新时刻)
🤔为何不以电平触发,而以边缘触发
电平触发意味着不断的扫描
边缘触发和脉冲触发某种程度上可以替代,即所有的脉冲信号也可触发边缘检测
并行性问题
🖥️代码示例
always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rw_cnt <= 1'b0; else if(rw_cnt == 6'd63) rw_cnt <= 1'b0; else rw_cnt <= rw_cnt + 1'b1; end //产生 RAM 写数据 always @(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) ram_wr_data <= 1'b0; else if(rw_cnt <= 6'd31) //在计数器的 0-31 范围内,RAM 写地址累加 ram_wr_data <= ram_wr_data + 1'b1; else ram_wr_data <= 1'b0 ; end
Copy
Verilog
当一个信号同出现在不同的alwasys语句块时候,且always触发条件相同,比如代码中的rw_cnt
则以always触发条件前的一瞬间作为输出来运行
assign语句
🤔电平检测→边缘检测互换定理(右表达式仅一个信号)
假设assign A = B
由于assign语句相当于逻辑门的直接连接
等效的为 A = B逻辑电平时刻相同
考虑所有信号时间太过于麻烦了,仅考虑B变化的时刻
当B变化时,可在B变换后的一瞬间采样作为表达式的输入
右表达式多个信号
可将assign信号变换的时刻为 其任一表达式信号变化的时,assign信号也跟着变化
但与always @(*)不同的是,变化瞬间的右边
两种设计逻辑
assign绑定CNT形式
不创建除了CNT之外的其他Reg变量
如果需要创建其他Reg,和CNT之间至少有一层wire隔离
二.组件编写实践
信号同步组件
🖥️信号同步代码
//对UART接收端口的数据延迟两个时钟周期 always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin uart_rxd_d0 <= 1'b0; uart_rxd_d1 <= 1'b0; end else begin uart_rxd_d0 <= uart_rxd; uart_rxd_d1 <= uart_rxd_d0; end end
Copy
Verilog
对于外界输入的信号,如果信号的变化与自身的时钟不同步,先需要进行同步化
同步化(Self Define): 即信号只能在系统更新时刻(Self Def)发生变化
uart_rxd 为非同步信号,则uart_rxd_d0为其同步化信号
uart_rxd 为同步信号,则uart_rxd_d0为其延迟一个时刻(拍)的信号
同步化信号的边缘检测组件
🖥️同步化信号的边缘检测
assign start_flag = uart_rxd_d1 & (~uart_rxd_d0); //此为下降沿检测
Copy
Verilog
其输出为单位脉冲响应(离散形式)
脉冲延迟问题
🖼️图示
若原始信号uart_rxd刚好在系统更新时刻变换,则边缘检测脉冲在下一拍才出现
但是由于采用了assign 边缘检测组件始终同已同步的信号下降沿同时出现
三.模块编写指南
USART_ Receive/Send模块
🖼️USART时序
下降沿检测组件: 检测从Idle(高电平)到起始信号,并提供一个trans_flag标志,表示整个接受周期时候trans_flag=1
Bit周期计数器: 根据 系统更新频率(System CLK)/Bound_Rate = 每比特的计数周期
当前Bit计数器: 每次Bit周期计数器重装载,后到下一各比特加一
串行/并行转换: 唯一的不同