一个很好的解释阻塞赋值与非阻塞赋值的例子

阻塞与非阻塞赋值详解
本文通过具体的Verilog代码示例对比了阻塞赋值与非阻塞赋值的区别,阐述了两者在综合过程中的不同表现,并讨论了它们在实际应用中的注意事项。

一个很好的解释阻塞赋值与非阻塞赋值的例子

复制代码
 1 module bnbasm  (/*AUTOARG*/
 2    // Outputs
 3    q1, q2,
 4    // Inputs
 5    clk_osc
 6    ) ;
 7    input clk_osc;
 8    output [7:0] q1,q2;
 9 
10    reg [7:0] q1,q2;
11    always @(posedge clk_osc)
12      begin
13      q1=q1+8'd1;
14      q2=q1;
15      end
16 endmodule //
复制代码

 

这段代码综合出的RTL模型为:
将过程块中的赋值语句改成非阻塞赋值:
1    always @(posedge clk_osc)
2      begin
3      q1<=q1+8'd1;
4      q2<=q1;
5      end

 

则综合出来的RTL模型为:
 
  阻塞语句和非阻塞语句的认识是教科书上的:阻塞赋值语句在所在的块中是按从上到下执行,而非阻塞赋值为并发执行。难理解的地方在于阻塞赋值的“从上到下执行”,这个说法很容易会被理解成时间上的先后顺序,会认为这些赋值语句之前会有延时存在。但是这个延时是指的什么延时,怎么安排的这些延时,会往这方面去想,觉得哪里都不合理,因此会产生疑惑。
  仔细观察两个RTL模型,就感觉恍然大悟,原来阻塞赋值的“从上到下执行”是通过空间逻辑结构来实现的,延时什么的根本跟这个没有关系。
  至于通常的说法“组合逻辑使用阻塞赋值,时序逻辑使用非阻塞幅值”并不是准确的。阻塞赋值跟非阻塞赋值的混用也有可能会是设计的需要,至于Quartus里面对两种赋值混用的报警,设计者应该检查下是不是无意的行为,因为这个可能是会导致意外的结果的。
 
注:初学verilog的时候没有多关注这些小细节,没有多使用RTL viewer这些有用的工具,以后还是要多补补课啊。
《Verilog HDL 应用程序设计实例精讲》是一本好书啊,感觉比夏宇闻的那本入门书好多了。
### 非阻塞赋值在编程中的实现与应用 #### 理解非阻塞赋值 在编程中,特别是在硬件描述语言(如Verilog)和某些系统级编程(如Linux设备驱动)中,“非阻塞赋值”是一种特殊的赋值机制,它允许程序在执行赋值操作时不会立即完成,而是允许其他操作或进程在此期间继续执行。这种机制常用于并行处理、任务调度以及避免资源竞争等问题。 在 **Verilog** 中,非阻塞赋值使用 `<=` 运算符[^4]。与阻塞赋值不同,非阻塞赋值不会等待当前语句执行完成后再执行下一条语句,而是在同一时间步结束后统一更新所有非阻塞赋值的结果。这种方式更接近于实际的硬件行为,因为多个寄存器更新可以同时发生。 例如: ```verilog always @(posedge clk) begin a <= b; b <= a; end ``` 在这个例子中,`a` 和 `b` 的更新是并发进行的,而不是顺序进行的。这是非阻塞赋值一个关键特性,特别适用于时序逻辑电路的设计[^1]。 #### 在FPGA设计中的应用 在 FPGA 设计中,非阻塞赋值主要用于描述时序逻辑。由于 FPGA 是基于同步时钟工作的,因此非阻塞赋值能够很好地模拟寄存器的行为。每个时钟上升沿触发一次状态更新,而非阻塞机制确保了在同一时钟周期内多个变量的更新不会互相干扰。 一个典型的例子是移位寄存器的实现: ```verilog module shift_register(clk, din, dout); input clk, din; output reg [3:0] dout; always @(posedge clk) begin dout[3] <= dout[2]; dout[2] <= dout[1]; dout[1] <= dout[0]; dout[0] <= din; end endmodule ``` 此代码中,所有的输出位都在同一个时钟沿被更新,利用了非阻塞赋值的并发性,从而实现了高效的时序逻辑设计。 #### 在Linux设备驱动中的应用 在 Linux 内核编程中,"非阻塞 I/O" 是一种常见的机制,用于处理设备读写操作。当设备无法立即完成请求时,进程可以选择不等待,而是返回错误码(如 `-EAGAIN` 或 `-EWOULDBLOCK`),从而避免长时间挂起。这种模式通常通过文件标志 `O_NONBLOCK` 来启用。 以下是一个简化版的非阻塞写操作示例: ```c static ssize_t xxx_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { int avail; int ret = count; DECLARE_WAITQUEUE(wait, current); add_wait_queue(&xxx_wait, &wait); do { avail = device_writable(); // 检查设备是否可写 if (avail < 0) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; goto out; } set_current_state(TASK_INTERRUPTIBLE); schedule(); // 让出CPU if (signal_pending(current)) { ret = -ERESTARTSYS; goto out; } } } while (avail < 0); device_write(buffer); // 实际写入设备 out: remove_wait_queue(&xxx_wait, &wait); set_current_state(TASK_RUNNING); return ret; } ``` 此段代码展示了如何在设备不可用时选择非阻塞方式退出,而不是陷入无限等待[^5]。 #### Python 中的非阻塞编程 在 Python 中,虽然没有直接的“非阻塞赋值”概念,但可以通过异步编程模型(如 `asyncio`)和多进程/多线程库来实现类似的效果。例如,在 `multiprocessing.Pool` 中,`apply_async()` 方法是非阻塞的,允许主程序继续执行而不必等待子进程完成任务。 示例: ```python from multiprocessing import Pool import time def f(x): time.sleep(2) return x*x if __name__ == &#39;__main__&#39;: with Pool(4) as pool: result = pool.apply_async(f, (10,)) print("继续执行其他任务...") print(result.get()) # 可选地获取结果 ``` 上述代码中,`apply_async()` 不会阻塞主线程,主线程可以继续执行其他任务,直到需要获取结果时才可能阻塞[^3]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值