Menu
CoddyTech

Двунаправленные порты

Часть раздела Основы путешествия по Verilog на Coddy. Урок 32 из 90.

Порт inout — это двунаправленный порт, который может как отправлять, так и принимать сигналы. В разное время он может работать как вход или выход. Большинство портов — либо input (данные поступают внутрь), либо output (данные передаются наружу). Порт inout может делать и то и другое. В зависимости от ситуации он может передавать данные наружу или принимать их.

Представь себе улицу с двусторонним движением, а не дорогу с односторонним.

Порты ввода-вывода используются для:

  • Общих шин: несколько устройств подключены к одним и тем же проводам
  • Шин данных памяти: данные можно считывать или записывать
  • Двунаправленной связи: I2C, SPI и т. д.

В каждый момент времени шину управляет только одно устройство. Остальные устройства должны находиться в состоянии высокого импеданса (Z).

Объявление двунаправленного порта

inout [7:0] data_bus;   // 8-битная двунаправленная шина
inout ready;             // Однобитный двунаправленный сигнал

Как работает Inout

Порту inout нужен управляющий сигнал, который определяет, работает ли он как вход или выход:

module bidir (
  inout [7:0] bus,
  input [7:0] data_out,
  input enable,
  output [7:0] data_in
);
  
  assign bus = (enable) ? data_out : 8'bZ;  // Drive bus when enabled, else Z
  assign data_in = bus;                     // Always read the bus
  
endmodule
  • Когда enable = 1, модуль управляет шиной (режим вывода)
  • Когда enable = 0, модуль освобождает шину (режим ввода, высокоимпедансное состояние)

Важные правила для Inout

ПравилоПочему
Должен быть объявлен как wireНе может быть reg
Несколько устройств не должны одновременно управлять шинойКонфликтующие драйверы приводят к X
Используй Z, чтобы освободить шинуЭто позволяет другим устройствам управлять шиной
Только один драйвер одновременноЭто предотвращает конфликт на шине

Inout и Input и Output

Тип портаНаправлениеМожет управлятьМожет считывать
inputВ одну сторону (только вход)НетДа
outputВ одну сторону (только выход)ДаДа (значение, которым он управляет)
inoutВ обе стороныДа (если включён)Да (всегда)

Распространённая ошибка

// НЕВЕРНО: Нельзя присваивать значение inout внутри блока always
always @(posedge clk) begin
  data_bus <= something;   // Ошибка! Используйте assign с условием
end

// ВЕРНО: Используйте assign с условием enable
assign data_bus = (enable) ? something : 8'bZ;
challenge icon

Задание

Добавь отсутствующий порт inout и инструкции assign, чтобы этот двунаправленный буфер работал.

Что нужно сделать:

  1. Добавь 8-битный порт inout с именем io_bus
  2. Добавь инструкцию assign, которая передаёт значение send_value на io_bus, когда send_enable равно 1, а в противном случае — Z
  3. Добавь инструкцию assign, которая считывает значение с io_bus в receive_value

Попробуйте сами

module bidir_buffer (
  // Задание 1: Добавьте здесь 8-битный двунаправленный порт io_bus
  
  
  input [7:0] send_value,
  input send_enable,
  output [7:0] receive_value
);

  // Задание 2: Добавьте оператор assign, который подаёт значение send_value на io_bus, когда send_enable равен 1, а в противном случае — Z
  
  
  // Задание 3: Добавьте оператор assign, который передаёт значение io_bus в receive_value
  

endmodule
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Основы

Потренируйтесь самостоятельно: Онлайн-компилятор Verilog