这篇是关于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
复制代码
- always @(posedge clk or posedge rst)表示每当clk上升沿或rst上升沿时,这个块中的代码会被实行。
- 触发条件是“边沿触发”(edge-sensitive),即代码只会在信号的边沿(上升或下降)发生变化时实行,而不会响应信号的电平状态。
- 在块的开头,我们首先检查复位信号rst是否为高电平(有效),如果是,则将leds重置为4’b0000。
- 这里的复位是异步的,因为复位发生时不必要等待时钟上升沿,只要rst变为高电平就立刻重置。
- 如果复位信号不为高电平(即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
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |