Question

I'm having a heck of a time trying to figure out how to connect the core generated Block RAM of a Xilinx Spartan 6 FPGA up to a bidirectional data bus. All the examples I can find say to just use the in and out data ports individually, but in my case I am forced to use it as a bidirectional data bus.

I am using VHDL.

The generated component has the following definition:

COMPONENT ram
    PORT (
       clka  : IN STD_LOGIC;
       wea   : IN STD_LOGIC_VECTOR(0 DOWNTO 0);
       addra : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
       dina  : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
       douta : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
    );
END COMPONENT;

Which is instantiated as follows:

ram1 : ram
  PORT MAP (
    clka => clk,
    wea => r_w,
    addra => addr,
    dina => din,
    douta => dout
  );

Can someone show me a process block that will connect dina and douta to an inout port called data?

I tried the following, with 0% success:

process(clk)
begin
  if rising_edge(clk) then
    if r_w = "1" then
      -- Write
      din <= data;
      dout <= temp;
    else
      -- Read
      din <= (others => 'Z');
      data <= dout;
    end if;
  end if;
end process;

Thank you for your assistance!

Was it helpful?

Solution

First of all, it's important to understand that internally to a modern FPGA (such as the Xilinx Spartan-6 you are talking about), there is not really any true bidirectional routing. Real bidirectional/tristate signals can only be used on I/O pins. Internal bidirectional/tristate signals can be emulated, but this is generally only done for interfacing with legacy HDL, not for anything new.

Now, regardless of whether there was true tristate or not, in order to hook up unidirectional dina and douta to the a "bidirectional" data, you need some signal to control when the memory is driving or not. Since we have short names already, let's just call it oe for "output enable". This signal will need to be controlled by your design in a way that make sense.

Given that, you can turn your two unidirectional signals in different directions plus your output enable direction selector into a logically bidirectional data bus with the following concurrent code (not in a process):

dina <= data;
data <= douta when oe = '1' else (others => 'Z');

OTHER TIPS

In the if r_w = "1" block, you appear to be trying to drive to your dout signal, which should be driven by the port douta. That might explain one problem (unless temp is all 'Z's).

Caveat for the following: I don't have anything to test this on right now, so it's all off the top of my head. Let me know if it's not helpful!

I don't think that a synchronous process is the best way to approach this. It's been a while since I've needed to do this, but here's what I think you need. Note that it's not a process, it goes right in the architecture.

din <= data when (r_w = '1') else (others => 'Z');
data <= dout when (r_w = '0') else (others => 'Z');

Explanation: when signals are being driven (or assigned to) by multiple sources, all but one of them must be 'Z'. The second line sets data to be driven by 'Z' — but this actually "frees it up" (from the point of view of the resolver) to be driven by the port.

If you do need this to be synchronous, this should be trivial to adapt — but remember that '0' and '1' aren't the only possible cases for std_logic, so think about an else clause or others in a case block!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top