Verilog双inout端口模块双向传输及固定方向实现技术咨询
问题1:是否存在可行的实现方案?
首先,你给出的示例代码存在严重问题:直接对两个inout端口互相赋值会形成组合逻辑环路,导致仿真和硬件中出现不确定的状态,而且没有考虑inout端口的三态特性——双向端口在不作为输出驱动时必须处于高阻态,否则会和外部驱动冲突。
不过确实存在可行的实现方案,核心是利用三态缓冲器,通过检测端口的输入状态来动态切换传输方向,同时保证非传输阶段端口处于高阻(等待状态)。以下是符合要求的Verilog实现:
module blackbox (inout left, inout right); reg left_drive_en, right_drive_en; reg left_out_val, right_out_val; // 检测输入端口的有效信号,切换驱动方向 always @(*) begin // 当left端口被外部驱动(非高阻),驱动right端口 if (left !== 1'bz) begin right_out_val = left; right_drive_en = 1'b1; left_drive_en = 1'b0; // left保持高阻,作为输入 end // 当right端口被外部驱动,驱动left端口 else if (right !== 1'bz) begin left_out_val = right; left_drive_en = 1'b1; right_drive_en = 1'b0; // right保持高阻,作为输入 end // 等待状态:所有端口高阻 else begin left_drive_en = 1'b0; right_drive_en = 1'b0; end end // 三态赋值:仅在驱动使能有效时输出,否则高阻 assign left = left_drive_en ? left_out_val : 1'bz; assign right = right_drive_en ? right_out_val : 1'bz; // 时序延迟规范(保留你原有的需求) specify (left => (right:1'b1)) = 7; (right => (left:1'b1)) = 8; endspecify endmodule
这个实现的逻辑是:
- 当外部驱动
left端口时,模块将right驱动为left的信号值,同时left保持高阻(作为输入); - 当外部驱动
right端口时,模块将left驱动为right的信号值,同时right保持高阻; - 当没有外部驱动时,两个端口都处于高阻态,等待输入。
完全满足你要求的仅两个inout端口、双向传输、非传输阶段等待的需求。
问题2:布局后固定传输方向,能否内部编码实现?
当然可以!我们可以通过Verilog参数化来实现,在模块定义时加入一个方向参数,实例化模块时根据布局位置指定该参数即可,不需要额外端口。
以下是实现代码:
module blackbox #( // 参数定义:可选"LEFT_TO_RIGHT"或"RIGHT_TO_LEFT",默认左到右 parameter TRANSMIT_DIRECTION = "LEFT_TO_RIGHT" ) (inout left, inout right); // 用generate块根据参数选择不同的逻辑 generate if (TRANSMIT_DIRECTION == "LEFT_TO_RIGHT") begin // 左到右传输:left作为输入(高阻),right作为输出驱动left的值 assign right = left; assign left = 1'bz; end else if (TRANSMIT_DIRECTION == "RIGHT_TO_LEFT") begin // 右到左传输:right作为输入(高阻),left作为输出驱动right的值 assign left = right; assign right = 1'bz; end endgenerate // 对应方向的时序延迟规范 specify if (TRANSMIT_DIRECTION == "LEFT_TO_RIGHT") begin (left => (right:1'b1)) = 7; end else begin (right => (left:1'b1)) = 8; end endspecify endmodule
使用时,根据布局位置实例化:
// 布局为左到右传输的实例 blackbox #(.TRANSMIT_DIRECTION("LEFT_TO_RIGHT")) bb_left (.left(signal_a), .right(signal_b)); // 布局为右到左传输的实例 blackbox #(.TRANSMIT_DIRECTION("RIGHT_TO_LEFT")) bb_right (.left(signal_c), .right(signal_d));
参数是在编译阶段确定的,完全符合"布局完成后确定传输方向"的需求,而且不需要添加任何额外端口。
内容的提问来源于stack exchange,提问作者M.Eren Çelik




