Verilog实战学习到RiscV - 4 : ICEStick 评估板计数器

这篇是关于always 时序逻辑的。直接上代码。

引脚配置文件

set_io  leds[0]  99
set_io  leds[1]  98
set_io  leds[2]  97
set_io  leds[3]  96

set_io  -pullup yes pmod[0]  78
set_io  -pullup yes pmod[1]  79

参看icestick的原理图
请添加图片描述

这里在pmod上使用了内部的上拉电阻。

代码

module top_counter (
    input [1:0] pmod,  // 对应icestick IO
    output reg [3:0] leds   // reg: 综合工具Yosys会将leds连接到D-FF
);
    wire clk;
    wire rst;
    assign clk = ~pmod[0];
    assign rst = ~pmod[1];

    always @(posedge clk or posedge rst) begin
        if (rst == 1'b1) begin
            leds <= 4'b0000;
        end 
        
        if (clk == 1'b1) begin
            leds <= leds + 1'b1;
        end

    end
endmodule

这段时序逻辑电路在使用Yosys 综合的时候产生了如下错误:

Creating register for signal `\SB_DFFES.\Q' using process `\SB_DFFES.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:803$203'.
  created $adff cell `$procdff$447' with positive edge clock and positive level reset.
Creating register for signal `\SB_DFFESS.\Q' using process `\SB_DFFESS.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:742$196'.
  created $dff cell `$procdff$448' with positive edge clock.
Creating register for signal `\SB_DFFER.\Q' using process `\SB_DFFER.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:662$192'.
  created $adff cell `$procdff$449' with positive edge clock and positive level reset.
Creating register for signal `\SB_DFFESR.\Q' using process `\SB_DFFESR.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:601$185'.
  created $dff cell `$procdff$450' with positive edge clock.
Creating register for signal `\SB_DFFS.\Q' using process `\SB_DFFS.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:527$182'.
  created $adff cell `$procdff$451' with positive edge clock and positive level reset.
Creating register for signal `\SB_DFFSS.\Q' using process `\SB_DFFSS.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:477$179'.
  created $dff cell `$procdff$452' with positive edge clock.
Creating register for signal `\SB_DFFR.\Q' using process `\SB_DFFR.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:406$176'.
  created $adff cell `$procdff$453' with positive edge clock and positive level reset.
Creating register for signal `\SB_DFFSR.\Q' using process `\SB_DFFSR.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:356$173'.
  created $dff cell `$procdff$454' with positive edge clock.
Creating register for signal `\SB_DFFE.\Q' using process `\SB_DFFE.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:311$171'.
  created $dff cell `$procdff$455' with positive edge clock.
Creating register for signal `\SB_DFF.\Q' using process `\SB_DFF.$proc$/usr/local/bin/../share/yosys/ice40/cells_sim.v:271$169'.
  created $dff cell `$procdff$456' with positive edge clock.
Creating register for signal `\top_counter.\leds' using process `\top_counter.$proc$top_counter.v:13$383'.
ERROR: Multiple edge sensitive events found for this signal!
make: *** [Makefile:23: top_counter.json] Error 1

两个if语句处理两种情况没有问题啊? 但其实,这是一个典型的C语言嵌入式程序猿会犯的典型错误。以下详细解释。

时钟和复位信号的处理

在时序逻辑设计中,always块的触发条件决定了什么时候执行其中的逻辑。在Verilog代码中,我们需要处理两个信号:

时钟信号(clk):通常用于在每个时钟周期(上升沿或下降沿)更新状态。
复位信号(rst):通常用于在复位条件下重置状态,一般来说是异步复位,即不依赖时钟。

为什么不在always块内部检查时钟电平?

  • 冗余:在always块中检查clk == 1’b1是多余的,因为我们已经在触发条件中指定了posedge clk,这意味着我们只在clk上升沿时执行代码。在执行代码时,clk必然处于高电平,因此再检查clk的电平是多余的。

  • 潜在错误:在时序逻辑中直接检查时钟的电平可能导致不一致或错误的行为,特别是在综合工具和仿真环境中。

这就解释了Yosys 所报的错误:

ERROR: Multiple edge sensitive events found for this signal!

正确的设计方式

在时序逻辑设计中,我们不应该在always块内部检查时钟信号的电平(例如clk == 1’b1),因为我们已经在always块的触发条件中指定了对时钟上升沿的响应。对于复位信号,一般我们会处理为同步或异步复位,这取决于设计要求。代码中已经指定了posedge rst,这通常表示异步复位。

修正后的always块

always @(posedge clk or posedge rst) begin
    if (rst) begin
        leds <= 4'b0000; // 异步复位
    end else begin
        leds <= leds + 1'b1; // 时钟上升沿时计数
    end
end
  1. 触发条件:
  • always @(posedge clk or posedge rst)表示每当clk上升沿或rst上升沿时,这个块中的代码会被执行。
  • 触发条件是“边沿触发”(edge-sensitive),即代码只会在信号的边沿(上升或下降)发生变化时执行,而不会响应信号的电平状态。
  1. 复位处理:
  • 在块的开头,我们首先检查复位信号rst是否为高电平(有效),如果是,则将leds重置为4’b0000。
  • 这里的复位是异步的,因为复位发生时不需要等待时钟上升沿,只要rst变为高电平就立即重置。
  1. 计数逻辑:
  • 如果复位信号不为高电平(即rst无效),那么在时钟的上升沿,leds会递增1。
  • 这里的计数逻辑是同步的,因为计数操作仅在时钟的上升沿进行。

Makefile

上篇一条条输入命令有点麻烦,这次我写了一个 Makefile 方便很多。

# Define the top-level module and output files
TOP = top_counter
BLIF = top_counter.blif
JSON = top_counter.json
ASC = top_counter.asc
BIN = top_counter.bin
PCF = pinmap.pcf

# Define the Yosys, nextpnr, and icestorm commands
YOSYS_CMD = yosys -p "synth_ice40 -top $(TOP) -blif $(BLIF) -json $(JSON)" $(TOP).v
NEXTPNR_CMD = nextpnr-ice40 --hx1k --json $(JSON) --pcf $(PCF) --asc $(ASC)
ICEPACK_CMD = icepack $(ASC) $(BIN)
ICETIME_CMD = icetime -tmd hx1k $(ASC)
ICEPROG_CMD = iceprog $(BIN)

# Default target
all: $(BIN)

# Yosys synthesis
$(BLIF) $(JSON): $(TOP).v
	$(YOSYS_CMD)

# nextpnr place and route 
$(ASC): $(JSON) $(PCF)
	$(NEXTPNR_CMD)

# Icepack to create a binary file
$(BIN): $(ASC)
	$(ICEPACK_CMD)

# Timing analysis (optional)
timing: $(ASC)
	icetime -tmd hx1k $(ASC)

# Program the FPGA
program: $(BIN)
	iceprog $(BIN)

# Clean up
clean:
	rm -f $(BLIF) $(JSON) $(ASC) $(BIN)

.PHONY: all clean timing program

烧写

$ iceprog top_counter.bin 
init..
cdone: high
reset..
cdone: low
flash ID: 0x20 0xBA 0x16 0x10 0x00 0x00 0x23 0x72 0x21 0x19 0x05 0x00 0x58 0x00 0x21 0x16 0x07 0x17 0xCE 0x6D
file size: 32220
erase 64kB sector at 0x000000..
programming..
done.                 
reading..
VERIFY OK             
cdone: high
Bye.

结果

我没有按钮,就随便用几根线模拟一下按键按下的时候的GND 下降沿和 被内部上拉电阻上拉后的上升沿。

这里时钟用一根连线模拟,不然时钟跳得太快看不见led变化。后面我们可以做一个分频。

白线 = CLK
灰线 = RST

  • Count up
    请添加图片描述

请添加图片描述

  • Reset
    请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/694991.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构:旋转数组

方法1 &#xff08;三次逆置法&#xff09;&#xff1a; void reverse(int* nums, int start, int end) {while (start < end) {int temp nums[start];nums[start] nums[end];nums[end] temp;start;end--;} }void rotate(int* nums, int numsSize, int k) {k k % numsS…

Camtasia Studio怎么自动加字幕呢,Camtasia Studio有什么功能呢

在信息化高度发达的今天&#xff0c;视频作为一种直观、生动的信息表达方式&#xff0c;受到了越来越多人的青睐。无论是教育领域的教学视频&#xff0c;还是企业宣传的推广短片&#xff0c;甚至是个人创作的分享作品&#xff0c;都离不开一款优秀的视频编辑软件。Camtasia Stu…

uc/OS-III多任务程序

文章目录 一、实验内容二、实验步骤&#xff08;一&#xff09;基于STM32CubeMX建立工程&#xff08;二&#xff09;获取uc/OS-III源码&#xff08;三&#xff09;代码移植 三、修改mai.c文件四、实验现象 一、实验内容 学习嵌入式实时操作系统&#xff08;RTOS&#xff09;,以…

ssm613个性化旅游攻略定制系统设计与实现+jsp【已测试】

前言&#xff1a;&#x1f469;‍&#x1f4bb; 计算机行业的同仁们&#xff0c;大家好&#xff01;作为专注于Java领域多年的开发者&#xff0c;我非常理解实践案例的重要性。以下是一些我认为有助于提升你们技能的资源&#xff1a; &#x1f469;‍&#x1f4bb; SpringBoot…

数据结构笔记 3 串 数组 广义表

以下了解即可&#xff0c;暂时没发现有什么考点 参考&#xff1a; 【数据结构】——多维数组和广义表_数据结构loc-CSDN博客 相对应的题目&#xff1a; 他这个数组不是从0开始的&#xff0c;是从1开始的&#xff0c;所以为了配合公式要减1 下面这道题又不一样&#xff0c;它是…

C++从入门到精通(最详细教程,12万总结,带你掌握c++知识,涵盖大量知识点)

目录 一、面向对象的思想 二、类的使用 1.类的构成 2.类的设计 三、对象的基本使用 四、类的构造函数 1.构造函数的作用 2.构造函数的特点 3.默认构造函数 3.1.合成的默认构造函数 3.2.手动定义的默认构造函数 四、自定义的重载构造函数 五、拷贝构造函数 1.手动…

「React」RSC 服务端组件

前言 RSC&#xff08;React Server Components&#xff09;是React框架的一个新特性&#xff0c;它允许开发者编写只在服务器端渲染的组件。与传统的服务器端渲染&#xff08;SSR&#xff09;不同&#xff0c;RSC的目标是提升性能和用户体验&#xff0c;同时减少客户端加载的J…

vivado HW_ILA

HW_ILA 描述 集成逻辑分析器&#xff08;ILA&#xff09;调试核心允许您执行系统内监控 通过对内核上的调试探针&#xff0c;在实现的设计中对信号进行处理。您可以配置 ILA核心实时触发特定硬件事件&#xff0c;并在 以系统速度探测。 ILA调试核心可以通过从IP目录实例化ILA核…

windows软件手动设置开机自启

博主需求 由于很多线上课程使用outlook进行教学&#xff0c;课程链接都关联到outlook日历中了&#xff0c;只要保持outlook是打开的状态就能收到上课提醒&#xff0c;非常方便。 但是有时候会忘记打开outlook查看&#xff0c;我偶尔会错过一些提醒QAQ。 所以如何让outlook常…

重生奇迹MU剑士怎么连招

剑士有很多技能&#xff0c;所以在连招方面就比较有讲究了。我们先来看一下这些技能的介绍吧。 1技能&#xff1a;造成伤害&#xff0c;冷却3秒。 2技能&#xff1a;旋转造成范围伤害&#xff0c;冷却6秒。 3技能&#xff1a;突刺前方敌人&#xff0c;短暂眩晕&#xff0c;冷…

Codeforces Round 951 (Div. 2)C. Earning on Bets

Problem - C - Codeforces 合理的答案&#xff1a; 求出 k1 ~ kn 的最小公倍数lcm&#xff0c;如果 lcm/k1 lcm/k2 ... lcm/kn < lcm 即符合题意。 左边之和为我们付的总钱数&#xff0c;右边才是每次选择得到的钱数(都为lcm)。 直接拿1e9检查是否可以分即可&#xff…

【Redis学习笔记06】Jedis客户端(下)

Jedis客户端 1. 命令 1.1 Hash类型 Hash类型相信大家并不陌生&#xff0c;许多编程语言都有对应数据结构的实现&#xff0c;可能叫做哈希、字典、映射、关联数组&#xff0c;是相当重要的&#xff01; 在实际开发中非常常用在面试中也是高频考点 1.1.1 常见命令 HSET命令…

pytorch-数据增强

目录 1. Flip翻转2. Rotate旋转3. scale缩放4. crop裁剪5. 总结6. 完整代码 1. Flip翻转 上图中做了随机水平翻转和随机垂直翻转&#xff0c;翻转完成后转化成tensor 2. Rotate旋转 上图中作了2次旋转第一次旋转角度在-15<0<15范围内&#xff0c;随机出一个角度&#xf…

Java SE(Java Platform, Standard Edition)

Java SE&#xff08;Java Platform, Standard Edition&#xff09; 是Java平台的一个版本&#xff0c;面向桌面应用程序、服务器和嵌入式环境。Java SE提供了开发和运行Java应用程序的基础API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&…

Java 编译报错:找不到符号? 手把手教你排查解决!

Java 编译报错&#xff1a;找不到符号&#xff1f; 手把手教你排查解决&#xff01; 在 Java 开发过程中&#xff0c;我们经常会遇到编译器抛出 "找不到符号" 错误。这个错误提示意味着编译器无法在它所理解的范围内找到你所引用的类、变量或方法。这篇文章将带你一步…

Spring Security 应用详解

一、 集成SpringBoot 1.1 Spring Boot 介绍 Spring Boot 是一套 Spring 的快速开发框架&#xff0c;基于 Spring 4.0 设计&#xff0c;使用 Spring Boot 开发可以避免一些繁琐的工程 搭建和配置&#xff0c;同时它集成了大量的常用框架&#xff0c;快速导入依赖包&#xff0…

html--宇航员404

<!doctype html> <html> <head> <meta charset"utf-8"> <title>太空404</title><style> html {margin: 0;padding: 0;background-color: white; }body, html {width: 100%;height: 100%;overflow: hidden; }#svgContainer…

数据结构(C):二叉树前中后序和层序详解及代码实现及深度刨析

目录 &#x1f31e;0.前言 &#x1f688;1.二叉树链式结构的代码是实现 &#x1f688;2.二叉树的遍历及代码实现和深度刨析代码 &#x1f69d;2.1前序遍历 ✈️2.1.1前序遍历的理解 ✈️2.1.2前序代码的实现 ✈️2.1.3前序代码的深度解剖 &#x1f69d;2.2中序遍历 ✈…

【QT5】<总览五> QT多线程、TCP/UDP

文章目录 前言 一、QThread多线程 二、QT中的TCP编程 1. TCP简介 2. 服务端程序编写 3. 客户端程序编写 4. 服务端与客户端测试 三、QT中的UDP编程 1. UDP简介 2. UDP单播与广播程序 前言 承接【QT5】&#xff1c;总览四&#xff1e; QT常见绘图、图表及动画。若存在…

开启数字化校园解决方案,实现教育智能化

现代社会的教育面临诸多挑战&#xff0c;如何提高教育质量&#xff0c;实现教育智能化成为了当务之急。数字化校园解决方案应运而生&#xff0c;为学校提供了全新的教学模式和管理方式。本文将介绍数字化校园解决方案的重要性&#xff0c;以及如何开启数字化校园&#xff0c;实…