Non-blocking BSD socket connections

Non-blocking BSD socket connections

Situation: You set up a non-blocking socket and do a connect() that returns -1/EINPROGRESS or -1/EWOULDBLOCK. You select() the socket for writability. This returns as soon as the connection succeeds or fails. (Exception: Under some old versions of Ultrix, select() wouldn't notice failure before the 75-second timeout.)

Question: What do you do after select() returns writability? Did the connection fail? If so, how did it fail?

If the connection failed, the reason is hidden away inside something called so_error in the socket. Modern systems let you see so_error with getsockopt(,,SO_ERROR,,), but this isn't portable---in fact, getsockopt() can crash old systems. A different way to see so_error is through error slippage: any attempt to read or write data on the socket will return -1/so_error.

Sometimes you have data to immediately write to the connection. Then you can just write() the data. If connect() failed, the failure will be reported by write(), usually with the right connect() errno. This is the solution I supplied for IRC in 1990. Unfortunately, on some systems, under some circumstances, write() will substitute EPIPE for the old errno, so you lose information.

Another possibility is read(fd,&ch,0). If connect() succeeded, you get a 0 return value, except under Solaris, where you get -1/EAGAIN. If connect() failed, you should get the right errno through error slippage. Fatal flaw: under Linux, you will always get 0.

Another possibility is read(fd,&ch,1), but this leads to programming difficulties, since a character may in fact have arrived. Everything that reads the socket has to know about your pre-buffered character.

Another possibility is recv(,,,MSG_PEEK). Unfortunately, the recv() code for stream sockets was, historically, completely untested and a massive source of bugs. I'd steer clear of this.

Another possibility is to select() for readability. But this is wrong, because the connect() may have succeeded and data may have arrived before you had time to do a select().

Another possibility is getpeername(). If the socket is connected, getpeername() will return 0. If the socket is not connected, getpeername() will return ENOTCONN, and read(fd,&ch,1) will produce the right errno through error slippage. This is a combination of suggestions from Douglas C. Schmidt and Ken Keys.

Another possibility is a second connect(). This seems to be a strictly worse solution than getpeername(): it doubles network traffic if the connection failed (with some TCP stacks), and doesn't improve reliability. Ken Keys mentions that this works with SOCKS.


<think>好的,我现在要解决用户遇到的PDS报错:“Cannot mix blocking and non-blocking assignments to variable read_en”。这个问题出现在Verilog或SystemVerilog代码中,通常是因为在同一个always块中对同一个变量同时使用了阻塞赋值(=)和非阻塞赋值(<=)。我需要一步步分析可能的原因,然后给出解决方法。 首先,我应该回忆Verilog中阻塞和非阻塞赋值的区别。阻塞赋值是按顺序执行的,而非阻塞赋值是在块结束时并行更新的。如果在同一个always块中对同一变量混合使用这两种赋值方式,会导致仿真和综合工具无法确定正确的执行顺序,从而报错。 接下来,用户可能需要了解具体的代码示例。比如,用户可能在同一个always块中写了类似以下代码: always @(posedge clk) begin if (condition) begin read_en = 1'b1; // 阻塞赋值 end else begin read_en <= 1'b0; // 非阻塞赋值 end end 这里read_en在同一块中同时用了=和<=,导致冲突。 接下来,我需要解释为什么不能混用。阻塞赋值会立即更新变量,而非阻塞赋值则在块结束后更新。混用会导致仿真结果不确定,尤其在时序逻辑中,可能引起竞争条件,使得设计行为不可预测。 然后,解决方案应该是统一赋值方式。如果是组合逻辑,应该全部使用阻塞赋值;如果是时序逻辑(如时钟触发的always块),应该统一使用非阻塞赋值。例如,用户需要检查所有对read_en的赋值,确保在同一个always块中只用一种方式。 可能还需要检查是否有多个always块对同一变量进行赋值。比如,一个always块用阻塞,另一个用非阻塞,这种情况下即使分开块,但同一变量被不同块赋值也可能导致问题。不过根据报错信息,更可能是在同一块中混用。 另外,可能的其他情况是,在同一个块中不同的分支用了不同的赋值方式,比如if和else部分分别用了阻塞和非阻塞。需要统一修改为同一种。 最后,用户可能需要一个修改后的正确示例,比如将上述例子中的阻塞赋值改为非阻塞: always @(posedge clk) begin if (condition) begin read_en <= 1'b1; // 非阻塞 end else begin read_en <= 1'b0; // 非阻塞 end end 或者,如果是组合逻辑,使用阻塞赋值: always @(*) begin if (condition) begin read_en = 1'b1; // 阻塞 end else begin read_en = 1'b0; // 阻塞 end end 同时提醒用户,组合逻辑必须覆盖所有条件,避免锁存器生成。 总结步骤:定位所有对read_en的赋值,检查是否在同一块中混用,统一修改为同一种赋值方式,确保组合或时序逻辑的正确使用。</think>在Verilog/SystemVerilog设计中,出现`Cannot mix blocking and non-blocking assignments to variable read_en`报错,表示对同一个变量`read_en`同时使用了阻塞赋值(`=`)和非阻塞赋值(`<=`)。以下是逐步分析和解决方法: --- ### **步骤1:理解报错原因** - **阻塞赋值(`=`)**:立即生效,常用于组合逻辑(如`always @(*)`)。 - **非阻塞赋值(`<=`)**:在代码块结束时更新,用于时序逻辑(如`always @(posedge clk)`)。 - **冲突场景**:在同一个`always`块中对`read_en`混用了`=`和`<=`,导致仿真和综合工具无法确定赋值顺序。 --- ### **步骤2:定位问题代码** 检查所有对`read_en`赋值的`always`块。典型错误示例如下: ```verilog // 错误示例:混合赋值 always @(posedge clk) begin if (reset) read_en = 1'b0; // 阻塞赋值(错误!) else if (condition) read_en <= 1'b1; // 非阻塞赋值(正确) end ``` --- ### **步骤3:统一赋值方式** 根据逻辑类型选择一致的赋值规则: #### **情况1:时序逻辑(时钟驱动)** - **全部使用非阻塞赋值**(`<=`) ```verilog // 正确示例:统一非阻塞赋值 always @(posedge clk) begin if (reset) read_en <= 1'b0; // 非阻塞 else if (condition) read_en <= 1'b1; // 非阻塞 end ``` #### **情况2:组合逻辑(无时钟)** - **全部使用阻塞赋值**(`=`),并确保覆盖所有分支 ```verilog // 正确示例:统一阻塞赋值 always @(*) begin if (reset) read_en = 1'b0; // 阻塞 else if (condition) read_en = 1'b1; // 阻塞 else read_en = 1'b0; // 覆盖默认情况 end ``` --- ### **步骤4:检查多always块冲突** 确保`read_en`没有在其他`always`块中被不同赋值方式操作: ```verilog // 错误示例:多always块混合赋值 always @(posedge clk) begin read_en <= new_value; // 非阻塞 end always @(*) begin read_en = another_value; // 阻塞(冲突!) end ``` - **解决方法**:一个变量只能在一个`always`块中赋值,或统一所有赋值方式。 --- ### **总结** 1. **时序逻辑**:统一使用`<=`。 2. **组合逻辑**:统一使用`=`,并覆盖所有条件分支。 3. **禁止跨always块混用**:同一变量不可在多个块中以不同方式赋值。 通过以上步骤,可彻底解决混合赋值导致的PDS报错问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值