模拟信号和输入输出
简介
您可以使用 Analog
/inout
功能定义三态信号。添加这些功能的原因有:
能够将三态信号添加到顶层(它避免了必须用一些手写的 VHDL/Verilog 包装它们)。
允许定义包含
inout
引脚的黑盒。能够通过层次结构将黑盒的
inout
引脚连接到顶级inout
引脚。
由于这些功能只是为了方便而添加的,因此请不要尝试使用三态逻辑的其他花哨的东西。
如果您想对内存映射 GPIO 外设等组件进行建模,请使用 Spinal 标准库中的 TriState/TriStateArray 线束,它抽象了三态驱动程序的本质。
模拟信号
Analog
是一个关键字,它允许将信号定义为模拟信号,在数字世界中可能意味着 0
, 1
, 或 Z
(断开、高阻状态)。
例如:
case class SdramInterface(g : SdramLayout) extends Bundle {
val DQ = Analog(Bits(g.dataWidth bits)) // Bidirectional data bus
val DQM = Bits(g.bytePerWord bits)
val ADDR = Bits(g.chipAddressWidth bits)
val BA = Bits(g.bankWidth bits)
val CKE, CSn, CASn, RASn, WEn = Bool()
}
输入/出
inout
是允许您将 Analog
信号设置为双向(“in”和“out”)信号的关键字。
例如:
case class SdramInterface(g : SdramLayout) extends Bundle with IMasterSlave {
val DQ = Analog(Bits(g.dataWidth bits)) // Bidirectional data bus
val DQM = Bits(g.bytePerWord bits)
val ADDR = Bits(g.chipAddressWidth bits)
val BA = Bits(g.bankWidth bits)
val CKE, CSn, CASn, RASn, WEn = Bool()
override def asMaster() : Unit = {
out(ADDR, BA, CASn, CKE, CSn, DQM, RASn, WEn)
inout(DQ) // Set the Analog DQ as an inout signal of the component
}
}
输入/出包装器
InOutWrapper
是一个工具,允许您将组件的所有 master
TriState
/TriStateArray
/ReadableOpenDrain
线束转换为 inout(Analog(.. .))
信号。它允许您保持硬件描述不受任何 Analog
/inout
事物的影响,然后转换顶层以备综合。
例如:
case class Apb3Gpio(gpioWidth : Int) extends Component {
val io = new Bundle {
val gpio = master(TriStateArray(gpioWidth bits))
val apb = slave(Apb3(Apb3Gpio.getApb3Config()))
}
...
}
SpinalVhdl(InOutWrapper(Apb3Gpio(32)))
这将生成:
entity Apb3Gpio is
port(
io_gpio : inout std_logic_vector(31 downto 0); -- This io_gpio was originally a TriStateArray Bundle
io_apb_PADDR : in unsigned(3 downto 0);
io_apb_PSEL : in std_logic_vector(0 downto 0);
io_apb_PENABLE : in std_logic;
io_apb_PREADY : out std_logic;
io_apb_PWRITE : in std_logic;
io_apb_PWDATA : in std_logic_vector(31 downto 0);
io_apb_PRDATA : out std_logic_vector(31 downto 0);
io_apb_PSLVERROR : out std_logic;
clk : in std_logic;
reset : in std_logic
);
end Apb3Gpio;
而不是:
entity Apb3Gpio is
port(
io_gpio_read : in std_logic_vector(31 downto 0);
io_gpio_write : out std_logic_vector(31 downto 0);
io_gpio_writeEnable : out std_logic_vector(31 downto 0);
io_apb_PADDR : in unsigned(3 downto 0);
io_apb_PSEL : in std_logic_vector(0 downto 0);
io_apb_PENABLE : in std_logic;
io_apb_PREADY : out std_logic;
io_apb_PWRITE : in std_logic;
io_apb_PWDATA : in std_logic_vector(31 downto 0);
io_apb_PRDATA : out std_logic_vector(31 downto 0);
io_apb_PSLVERROR : out std_logic;
clk : in std_logic;
reset : in std_logic
);
end Apb3Gpio;
手动驱动模拟线束
如果 Analog
线束没有被驱动,它将默认为高阻态。因此,要手动实现三态驱动程序(以防因某种原因无法使用 InOutWrapper
类型),您必须有条件地驱动信号。
手动将 TriState
信号连接到 Analog
线束:
case class Example extends Component {
val io = new Bundle {
val tri = slave(TriState(Bits(16 bits)))
val analog = inout(Analog(Bits(16 bits)))
}
io.tri.read := io.analog
when(io.tri.writeEnable) { io.analog := io.tri.write }
}