Analog and inout

Introduction

You can define native tristate signals by using the Analog/inout features. These features were added for the following reasons:

  • Being able to add native tristate signals to the toplevel (it avoid having to manualy wrap them with some hand written VHDL/Verilog)

  • Allowing the definition of blackbox which contains some inout pins

  • Being able to connect a blackbox inout through the hierarchy to a toplevel inout pin.

As those feature were only added for convenance, do not do other fancy stuff with it and if you want to model a component like an memory mapped GPIO peripheral, please use the TriState/TriStateArray bundles from the spinal lib, which keep the true nature of the tristate driver.

Analog

Analog is the keyword which allows a signal to be defined as something … analog, which in the digital world could mean ‘0’, ‘1’, or ‘Z’.

For instance :

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

inout is the keyword which allows you to set an Analog signal as a component inout.

For instance:

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 of the component
  }
}

InOutWrapper

InOutWrapper is a tool which allows you to tranform all master TriState/TriStateArray/ReadableOpenDrain bundles of a component into native inout(Analog(…)) signals. It allow you to keep all your hardware description without any Analog/inout things, and then transform the toplevel to make it synthesis ready.

For instance:

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)))

Will generate:

entity Apb3Gpio is
  port(
    io_gpio : inout std_logic_vector(31 downto 0); -- This io_gpio was originaly 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;

Instead of:

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;