Issue with port buffering (inout) Spartan7 board

Status
Not open for further replies.

FlyingDutch

Advanced Member level 1
Joined
Dec 16, 2017
Messages
458
Helped
45
Reputation
92
Reaction score
55
Trophy points
28
Location
Bydgoszcz - Poland
Activity points
5,027
Hello,

I am trying to implement SRAM controller (on external PCB with CY7C1041DV33 SRAM IC) connected to QMTECH Spartan7 board. Here is link to Spartan7 board:

https://pl.aliexpress.com/item/32959887279.html?spm=a2g17.12010612.8148356.4.1a4954bdnHb81i

The PCB board and other details I described in this post:

https://www.edaboard.com/threads/static-ram-ic-selection-for-full-hd-resolution-frame-buffer.395013/

The project is written in VHDL and is based on this Github project (for Altera DE1 FPGA board)

https://github.com/chkrr00k/sram-controller

I modified it a bit - here are sources in VZHDL:

"sramTest.vhd"


Code:
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
use work.all;

entity sramTest is
    port(
        CLOCK_50    : in std_logic;
        KEY            : in std_logic;
        RESET_N     : in std_logic;
        LEDR        : out std_logic;
        LEDG        : out std_logic;
                
        SRAM_ADDR           : out   std_logic_vector(17 downto 0);
        SRAM_DQ             : inout std_logic_vector(15 downto 0);
        SRAM_CE_N           : out   std_logic;
        SRAM_OE_N           : out   std_logic;
        SRAM_WE_N           : out   std_logic;
        SRAM_UB_N           : out   std_logic;
        SRAM_LB_N           : out   std_logic
        
    );
end;

architecture RTL of sramTest is
    signal clock        : std_logic;
    signal clockVGA    : std_logic;
    --signal RESET_N        : std_logic;
    
    signal data : std_logic_vector(7 downto 0);
    signal addr : std_logic_vector(17 downto 0);
    signal i : std_logic_vector(15 downto 0);
    signal o : std_logic_vector(15 downto 0);
    signal w : std_logic;
        
begin   
        test : entity work.test
        port map(
            CLOCK => clock,
            RESET_N => RESET_N,
                    
            LEDG => LEDG,
            LEDR => LEDR,
            KEY => KEY,       
            DATA => data,           
            I => i,
            O => o,
            ADDR => addr,
            W => w
        );
        
        sram : entity work.sram
        port map(
            CLOCK => clock,
            RESET_N => RESET_N,
            
            ACTION => w,
            
            DATA_OUT => o,
            DATA_IN => i,
            ADDR => addr,
            
            SRAM_ADDR => SRAM_ADDR,
            SRAM_DQ   => SRAM_DQ,           
            SRAM_CE_N => SRAM_CE_N,
            SRAM_OE_N => SRAM_OE_N,
            SRAM_WE_N => SRAM_WE_N,
            SRAM_UB_N => SRAM_UB_N,
            SRAM_LB_N => SRAM_LB_N       
        );

end architecture;

"test.vhd"

Code:
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
use work.all;

entity test is
    port (
        CLOCK      : in std_logic; -- clock in
        RESET_N     : in std_logic; -- reset async
        
        LEDG     : out std_logic;
        LEDR     : out std_logic;
        KEY      : in std_logic;       
        DATA     : in std_logic_vector(7 downto 0);
        
        I        : out std_logic_vector(15 downto 0);
        O        : in std_logic_vector(15 downto 0);
        W        : out std_logic;
        ADDR    : out std_logic_vector(17 downto 0)
    );
end entity;

architecture behav of test is
    signal S_HC : integer range 0 to 9;
    signal S_LC : integer range 0 to 9;
    signal i_value : integer range 0 to 99;
    
    signal S_READ : std_logic_vector(15 downto 0);
begin

    Test : process(CLOCK, RESET_N)
    begin
        if rising_edge(CLOCK) then
            LEDG <= '0';
            LEDR <= '0';
            if KEY = '0' then
                ADDR <= "000000000000000000";
                I <= "00000000" & DATA;
                W <= '1';
                LEDG <= '1';
            elsif KEY = '0' then
                ADDR <= "000000000000000000";
                S_READ <= O;
                W <= '0';
                LEDR <= '1';
            end if;
        end if;
    end process;

end architecture;

"sram.vhd"

Code:
library ieee;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
use work.all;

entity sram is
    port (
        CLOCK         : in std_logic; -- clock in
        RESET_N        : in std_logic; -- reset async
        
        DATA_IN     : in std_logic_vector(15 downto 0); -- data in
        DATA_OUT    : out std_logic_vector(15 downto 0); -- data out
        ADDR            : in std_logic_vector(17 downto 0); -- address in
        
        ACTION        : in std_logic; -- operation to perform
        
        SRAM_ADDR    : out std_logic_vector(17 downto 0); -- address out
        SRAM_DQ     : inout std_logic_vector(15 downto 0); -- data in/out
        SRAM_CE_N   : out std_logic; -- chip select
        SRAM_OE_N   : out std_logic; -- output enable
        SRAM_WE_N   : out std_logic; -- write enable
        SRAM_UB_N   : out std_logic; -- upper byte mask
        SRAM_LB_N   : out std_logic -- lower byte mask
        
    );
end entity;

architecture behav of sram is
    -- ram fsm
    type RAM_FSM_T is (
        OFF_F,
        READ_F,
        WRITE_F
    );
    signal S_RAM_STATE : RAM_FSM_T := OFF_F;
    -- controller state;
    signal S_ACTION : std_logic; -- [0 - read] [1 - write]
    signal S_READ : std_logic_vector(15 downto 0);
    
begin   
    
    RamController : process(CLOCK,RESET_N)
    begin
        if(RESET_N = '1') then -- async reset
            S_READ <= "0000000000000000"; -- reset the data read signal
            SRAM_CE_N<='0'; -- enables the chip (all the time?)
            SRAM_LB_N<='1'; -- mask low byte
            SRAM_UB_N<='1'; -- mask high byte
            SRAM_ADDR <= (others => '-'); -- set the address as "don't care" (must preserve low the bus)
            SRAM_DQ <= (others => 'Z'); -- set the data bus as high impedance (tristate)
        elsif rising_edge(CLOCK) then -- high clock state (do something!)
            SRAM_ADDR <= (others => '-'); -- "don't care"
            SRAM_DQ <= (others => 'Z'); -- high impedance
            if ACTION = '0'  then -- READ
                S_ACTION <= '0'; -- tells the fsm to read
                SRAM_ADDR <= ADDR; -- notify the address
                SRAM_LB_N <='0'; -- unmask low byte
                SRAM_UB_N <='0'; -- unmask high byte
                DATA_OUT <= SRAM_DQ(15 downto 0); -- read the data
            elsif ACTION = '1'  then -- WRITE
                S_ACTION <= '1'; -- tells the fsm to write
                SRAM_ADDR <= ADDR; -- notify the address
                SRAM_LB_N <= '0'; -- unmask low byte
                SRAM_UB_N <= '0'; -- unmask high byte
                SRAM_DQ <= DATA_IN; -- send the data
            end if;
        end if;
    end process;
    
    FSM : process(S_ACTION)
    begin
        SRAM_OE_N <= '1'; -- output disabled
        SRAM_WE_N <= '1'; -- write disabled
        if(S_ACTION = '0') then
            --read
            S_RAM_STATE <= READ_F;
            SRAM_OE_N <= '0';
        else
            --write
            S_RAM_STATE <= WRITE_F;
            SRAM_WE_N <= '0';
        end if;
    end process;
    
end architecture;
--- Updated ---

Sorry i wasn't able to fit all in one message - here is continuation:

And here is constraint file "sramTest.xdc" for that FPGA boasrd with Spartan7:

Code:
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.CONFIG.UNUSEDPIN PULLUP [current_design]

#############SPI Configurate Setting##################
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]

############## clock and reset define##################
create_clock -period 20.000 -waveform {0.000 5.000} [get_ports CLOCK_50]
set_property PACKAGE_PIN H11 [get_ports CLOCK_50]
set_property IOSTANDARD LVCMOS33 [get_ports CLOCK_50]
###set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {CLK50MHz_IBUF}]

#Keys
set_property -dict {PACKAGE_PIN B6 IOSTANDARD LVCMOS33} [get_ports RESET_N]
set_property -dict {PACKAGE_PIN C5 IOSTANDARD LVCMOS33} [get_ports KEY]

#LEDs
set_property -dict {PACKAGE_PIN C4 IOSTANDARD LVCMOS33} [get_ports LEDR]
set_property -dict {PACKAGE_PIN L5 IOSTANDARD LVCMOS33} [get_ports LEDG]       

#SRAM_ADDR
set_property -dict {PACKAGE_PIN M5 IOSTANDARD LVCMOS33} [get_ports {SRAM_ADDR[17]}]
set_property -dict {PACKAGE_PIN M4 IOSTANDARD LVCMOS33} [get_ports {SRAM_ADDR[16]}]
......... shortened

#SRAM_DQ

set_property -dict {PACKAGE_PIN F4 IOSTANDARD LVCMOS33} [get_ports {SRAM_DQ[15]}]
#set_property IOB TRUE [get_ports {SRAM_DQ[15]}]
set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {SRAM_DQ[14]}]
#set_property IOB TRUE [get_ports {SRAM_DQ[14]}]
.... shortened

set_property -dict {PACKAGE_PIN B3 IOSTANDARD LVCMOS33} [get_ports {SRAM_DQ[1]}]
set_property -dict {PACKAGE_PIN A2 IOSTANDARD LVCMOS33} [get_ports {SRAM_DQ[0]}]

#sYGNALY STERUJACE sram ic
set_property -dict {PACKAGE_PIN A4 IOSTANDARD LVCMOS33} [get_ports SRAM_CE_N]
set_property -dict {PACKAGE_PIN A3 IOSTANDARD LVCMOS33} [get_ports SRAM_OE_N]
set_property -dict {PACKAGE_PIN C3 IOSTANDARD LVCMOS33} [get_ports SRAM_WE_N]
set_property -dict {PACKAGE_PIN D3 IOSTANDARD LVCMOS33} [get_ports SRAM_UB_N]
set_property -dict {PACKAGE_PIN A5 IOSTANDARD LVCMOS33} [get_ports SRAM_LB_N]

I have warnings in implementation phase that SRAM_DQ (inout) bus hasd no proper input and output buffer. Here is this warniing:

Code:
DRCNetlistPortRequired Buffer[DRC RPBF-3] IO port buffering is incomplete: Device port SRAM_DQ[0] expects both input and output buffering but the buffers are incomplete.
--- Updated ---

I tried to put IOBUF for port SRAM_DQ using as atributes in VHDL code or XDC file but they are ignored.

Could somebody to help me put IOBUF for SRAM_DQ port?

Thanks in advance anr Regards
 
Last edited:

When I am trying to put attributes for IOB primitives in xdc file like that:
Code:
#SRAM_DQ

set_property -dict {PACKAGE_PIN F4 IOSTANDARD LVCMOS33} [get_ports {SRAM_DQ[15]}]
set_property IOB TRUE [get_ports {SRAM_DQ[15]}]
set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {SRAM_DQ[14]}]
set_property IOB TRUE [get_ports {SRAM_DQ[14]}]
set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {SRAM_DQ[13]}]
set_property IOB TRUE [get_ports {SRAM_DQ[13]}]
.

I have in implementation phase such warnings:

[Constraints 18-5573] Port SRAM_DQ[15] has IOB constraint set, However, the instance SRAM_DQ_OBUFT[15]_inst_i_1 connected to it does not seem to have valid I/O connection to be placed into I/O. The constraint on the port will be ignored.

Could somebody tell me how to do it correctly?

Best Regards

Thanks in advance anr Regards
 

I'm pretty sure that "set_property IOB TRUE" is for requesting the placer to sticking flip-flops in the IOB and is not for requesting an IOBUF primitive to be used.

The use of inout along with a tri-state assignment is enough to inform the synthesis that an IOBUF primitive be used to implement the pin.
 
Hello @ads-ee ,

I have such assigment in "RamController":

Code:
RamController : process(CLOCK,RESET_N)
    begin
        if(RESET_N = '1') then -- async reset
            S_READ <= "0000000000000000"; -- reset the data read signal
            SRAM_CE_N<='0'; -- enables the chip (all the time?)
            SRAM_LB_N<='1'; -- mask low byte
            SRAM_UB_N<='1'; -- mask high byte
            SRAM_ADDR <= (others => '-'); -- set the address as "don't care" (must preserve low the bus)
            SRAM_DQ <= (others => 'Z'); -- set the data bus as high impedance (tristate)


so why I have such warning as that described in post #1?

Best Regards
 

Doing tri-state assignments in synchronous code is relying on the tools to understand that you are inferring a tri-state output pin from a flip-flop description. I don't recommend coding a tri-state that way.

I use code like this to infer a tri-state:
Code:
-- the tri-state  output
  sram_dq <= when sram_dq_hiz = '1' then (others => 'Z') else sram_dq_reg;

-- the process
ramcontroller : process(clock, reset_n)
    begin
        if (reset_n = '1') then
            sram_dq_hiz <= '1'; -- force hi-z
            sram_dq_reg <= (others => '0');

You can then use the set_property IOB to attempt to get the tools to put the sram_dq_reg and sram_dq_hiz into the corresponding IOB FFs. I find it's usually easier to instantiate the IOB primitives.
 
Hello @ads-ee,

I tried it but it is not working for me - I don't know how sram_dq_reg is related to sram_dq. sram_dq is tri-state data bus of my external SRAM IC (physically) and have to be connected to IC. I don't fully understand how further changes in code of "sram.vhd" should to be done. Maybe you can clarify that?

Best regards
 

sram_dq_reg replaces the sram_dq you had in your code snippet. It is just renamed so you can implement the tri-state in a separate line and connect that to the SRAM.

Here is an example of an SRAM interface I found after a quick search.
https://ece-research.unm.edu/jimp/vhdl_fpgas/slides/SRAM.pdf
Page 22 shows at the bottom the dio assignment which is the tri-state output to the SRAM device and the logic that drives the data is from the signal data_f2s_reg.
--- Updated ---

Look at the schematics they drew of the design and how the tri-state is a driver that connects to the registers.
 
Hello,

I tried different ways to inform synthesiis tool of Vivado that is needed tri-state buffor but without positive effect. So I decide to instantiae tri-state buffer in explicit way using "for generate" construct from VHDL. I made use of this WWW page:

http://forums.xilinx.com/t5/Process...I/Use-IOBUF-with-std-logic-vector/td-p/944861

The file "sram.vhd" in my project looks now like this:
Code:
library ieee;
library unisim;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
use unisim.vcomponents.all;
use work.all;

entity sram is
    port (
        CLOCK         : in std_logic; -- clock in
        RESET_N        : in std_logic; -- reset async
     
        DATA_IN     : in std_logic_vector(15 downto 0); -- data in
        DATA_OUT    : out std_logic_vector(15 downto 0); -- data out
        ADDR            : in std_logic_vector(17 downto 0); -- address in
     
        ACTION        : in std_logic; -- operation to perform
     
        SRAM_ADDR    : out std_logic_vector(17 downto 0); -- address out
        SRAM_DQ     : inout std_logic_vector(15 downto 0); -- data in/out
        SRAM_CE_N   : out std_logic; -- chip select
        SRAM_OE_N   : out std_logic; -- output enable
        SRAM_WE_N   : out std_logic; -- write enable
        SRAM_UB_N   : out std_logic; -- upper byte mask
        SRAM_LB_N   : out std_logic -- lower byte mask
     
    );
end entity;

architecture behav of sram is
    -- ram fsm
    type RAM_FSM_T is (
        OFF_F,
        READ_F,
        WRITE_F
    );
    signal S_RAM_STATE : RAM_FSM_T := OFF_F;
    -- controller state;
    signal S_ACTION : std_logic; -- [0 - read] [1 - write]
    signal S_READ : std_logic_vector(15 downto 0);
 
begin

GEN1: for i in 15 downto 0 generate  
     IOBx : IOBUF
         generic map(
             DRIVE => 12,
             IOSTANDARD => "LVCMOS33",
             SLEW => "FAST")
             port map (
             O => DATA_OUT(i),      -- Buffer output (data coming from SRAM)
             IO => SRAM_DQ(i),         -- Buffer inout port (connect directly to top-level port)
             I => DATA_IN(i),         -- Buffer input (data going to SRAM)
             T => S_ACTION              -- 3-state enable input, high=input, low=output
         );
end generate GEN1;
 
    RamController : process(CLOCK,RESET_N)
    begin
        if(RESET_N = '1') then -- async reset
            S_READ <= "0000000000000000"; -- reset the data read signal
            SRAM_CE_N<='0'; -- enables the chip (all the time?)
            SRAM_LB_N<='1'; -- mask low byte
            SRAM_UB_N<='1'; -- mask high byte
            SRAM_ADDR <= (others => '-'); -- set the address as "don't care" (must preserve low the bus)
            SRAM_DQ <= (others => 'Z'); -- set the data bus as high impedance (tristate)
        elsif rising_edge(CLOCK) then -- high clock state (do something!)
            SRAM_ADDR <= (others => '-'); -- "don't care"
            SRAM_DQ <= (others => 'Z'); -- high impedance
            if ACTION = '0'  then -- READ
                S_ACTION <= '0'; -- tells the fsm to read
                SRAM_ADDR <= ADDR; -- notify the address
                SRAM_LB_N <='0'; -- unmask low byte
                SRAM_UB_N <='0'; -- unmask high byte
                DATA_OUT <= SRAM_DQ(15 downto 0); -- read the data
            elsif ACTION = '1'  then -- WRITE
                S_ACTION <= '1'; -- tells the fsm to write
                SRAM_ADDR <= ADDR; -- notify the address
                SRAM_LB_N <= '0'; -- unmask low byte
                SRAM_UB_N <= '0'; -- unmask high byte
                SRAM_DQ <= DATA_IN; -- send the data
            end if;
        end if;
    end process;
 
    FSM : process(S_ACTION)
    begin
        SRAM_OE_N <= '1'; -- output disabled
        SRAM_WE_N <= '1'; -- write disabled
        if(S_ACTION = '0') then
            --read
            S_RAM_STATE <= READ_F;
            SRAM_OE_N <= '0';
        else
            --write
            S_RAM_STATE <= WRITE_F;
            SRAM_WE_N <= '0';
        end if;
    end process;
 
end architecture;

I tried to explicite instantiate "IOBUF" primitives in "for ...generate" VHDL languasge. There is not syntax errors in this code. When I run synthetise I got enigmatic error:

[Common 17-69] Command failed: Vivado Synthesis failed

without any explanation (see screen):


What I made inproper in this code? Here is also attached full "Synthesis Report".The error is in optimization phase of synthesis:


Code:
Finished Technology Mapping : Time (s): cpu = 00:00:36 ; elapsed = 00:00:37 . Memory (MB): peak = 1039.172 ; gain = 14.551
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
Start IO Insertion
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
Start Final Netlist Cleanup
---------------------------------------------------------------------------------
---------------------------------------------------------------------------------
Finished Final Netlist Cleanup
---------------------------------------------------------------------------------
ERROR: synthesis optimization failed, fatal insert_io failure.
Synthesis Optimization Runtime : Time (s): cpu = 00:00:33 ; elapsed = 00:00:43 . Memory (MB): peak = 1039.172 ; gain = 0.000
INFO: [Common 17-83] Releasing license: Synthesis
36 Infos, 2 Warnings, 0 Critical Warnings and 1 Errors encountered.
synth_design failed
ERROR: [Common 17-69] Command failed: Vivado Synthesis failed
INFO: [Common 17-206] Exiting Vivado at Sat Dec  5 11:21:45 2020...

Can somebody help me with this error?

BTW: the "IOBUF" primitive is for my surprise in library unisim, can this library be used in synthesis?

I attached ful Vivado project to thrad.

Best Regards
 

Attachments

  • SynthReport.txt
    18 KB · Views: 350
  • SRAM_CTRL_256Kx16_Altera.zip
    70.7 KB · Views: 134
Last edited:

First, I suggest to change a path to your project to be shorter - weird things can happen now.
Secound, consider OS change to Linux (significant longer path length than in Windows).
 
You are probably running into an issue with the use of the following code and the IOBUF primitive, which also why using a tri-state like I describe didn't work.

Code:
SRAM_DQ <= (others => 'Z'); -- set the data bus as high impedance (tristate)

I mentioned earlier that you should not be setting anything in a registered process with a Z as that implies a tri-state buffer. Set SRAM_DQ to either '0's or some other constant.

You really need to think of your code as being hardware circuits...e.g. 7400 series ICs and a bunch of wires on a breadboard.
 
Hello,

maybe I found solution. On this page is described how to steer direction of "IOBF" data:

http://ee427plblabs.groups.et.byu.net/wiki/doku.php?id=implementing_in-out_pins_in_xilinx_sdk

I changed the "sram.vhd" file like that:

Code:
library ieee;
library unisim;
use ieee.numeric_std.all;
use ieee.std_logic_1164.all;
use unisim.vcomponents.all;
use work.all;

entity sram is
    port (
        CLOCK         : in std_logic; -- clock in
        RESET_N        : in std_logic; -- reset async
      
        DATA_IN     : in std_logic_vector(15 downto 0); -- data in
        DATA_OUT    : out std_logic_vector(15 downto 0); -- data out
        ADDR        : in std_logic_vector(17 downto 0); -- address in
      
        ACTION        : in std_logic; -- operation to perform
      
        SRAM_ADDR    : out std_logic_vector(17 downto 0); -- address out
        SRAM_DQ     : inout std_logic_vector(15 downto 0); -- data in/out
        SRAM_CE_N   : out std_logic; -- chip select
        SRAM_OE_N   : out std_logic; -- output enable
        SRAM_WE_N   : out std_logic; -- write enable
        SRAM_UB_N   : out std_logic; -- upper byte mask
        SRAM_LB_N   : out std_logic -- lower byte mask
      
    );
end entity;

architecture behav of sram is
    -- ram fsm
    type RAM_FSM_T is (
        OFF_F,
        READ_F,
        WRITE_F
    );
    signal S_RAM_STATE : RAM_FSM_T := OFF_F;
    -- controller state;
    signal S_ACTION : std_logic; -- [0 - read] [1 - write]
    signal NEG_ACTION : std_logic; -- [0 - read] [1 - write]
    signal S_READ : std_logic_vector(15 downto 0);   
  
begin

NEG_ACTION <= not S_ACTION; --used for steering buffer direction

GEN1: for i in 15 downto 0 generate   
     IOBx : IOBUF
         generic map(
             DRIVE => 8,
             IOSTANDARD => "LVCMOS33",
             SLEW => "SLOW")
         port map (
             O => DATA_OUT(i),      -- Buffer output (data coming from SRAM)
             IO => SRAM_DQ(i),         -- Buffer inout port (connect directly to top-level port)
             I => DATA_IN(i),         -- Buffer input (data going to SRAM)
             T => NEG_ACTION        -- 3-state enable input, high=input, low=output
         );
end generate GEN1;
  
    RamController : process(CLOCK,RESET_N)
    begin
        if(RESET_N = '1') then -- async reset
            S_READ <= "0000000000000000"; -- reset the data read signal
            SRAM_CE_N<='0'; -- enables the chip (all the time?)
            SRAM_LB_N<='1'; -- mask low byte
            SRAM_UB_N<='1'; -- mask high byte
            SRAM_ADDR <= (others => '-'); -- set the address as "don't care" (must preserve low the bus)
            SRAM_DQ <= (others => 'Z'); -- set the data bus as high impedance (tristate)
        elsif rising_edge(CLOCK) then -- high clock state (do something!)
            SRAM_ADDR <= (others => '-'); -- "don't care"
            SRAM_DQ <= (others => 'Z'); -- high impedance
            if ACTION = '0'  then -- READ
                S_ACTION <= '0'; -- tells the fsm to read
                SRAM_ADDR <= ADDR; -- notify the address
                SRAM_LB_N <='0'; -- unmask low byte
                SRAM_UB_N <='0'; -- unmask high byte
                --DATA_OUT <= SRAM_DQ(15 downto 0); -- read the data
            elsif ACTION = '1'  then -- WRITE
                S_ACTION <= '1'; -- tells the fsm to write
                SRAM_ADDR <= ADDR; -- notify the address
                SRAM_LB_N <= '0'; -- unmask low byte
                SRAM_UB_N <= '0'; -- unmask high byte
                --SRAM_DQ <= DATA_IN; -- send the data
            end if;
        end if;
    end process;
  
    FSM : process(S_ACTION)
    begin
        SRAM_OE_N <= '1'; -- output disabled
        SRAM_WE_N <= '1'; -- write disabled
        if(S_ACTION = '0') then
            --read
            S_RAM_STATE <= READ_F;
            SRAM_OE_N <= '0';
        else
            --write
            S_RAM_STATE <= WRITE_F;
            SRAM_WE_N <= '0';
        end if;
    end process;
  
end architecture;

Now I haven't any synthesis or implementaion erros, but after implementation project use 0 LUTs 0 Flip-Flops etc. I am giving up - I don,t know how to force this code to working properly.

Best regards
 

I pulled you code from post #9 and this is what your elaborated design looks like:



As you can see the blue line represents the IO pin signal and it is going to internal registers and the Q output of the SRAM_DQ_reg[15:0] block. This is why I kept telling you to not assign anything in the edge sensitive process with Z.

Your code from post #12 produces the following when elaborated.


Once again there is an issue with SRAM_DQ_reg[15:] begin on the output of the OBUFT, which is wrong it should be only connected to the I port of the OBUFT. Once again you did not listen to what I told you and remove all Z's from any assignment in the process.
--- Updated ---

Note if you had run a simulation on this design then it would have show that you had two drivers on the SRAM_DQ net. As you are just compiling code and trying it on hardware (like a typical software coder) you end up with problems where you don't have a clue what is going on.

Learn to run simulations BEFORE you run implementation. Vivado has a built in simulator, so there is no excuse for not running simulations. Even with decades of experience, I will still run simulations on even simple stuff.
 
Last edited:
Hello @ads-ee ,

Thanks for such detail analysis of my problem. I agree - I should run simulation and I am going to do that with this code. You are right I am software developer and it is difficult for me to not think about code in HDL language "in way software developers do".

Thanks very much for your time and help

Best Regards
 

Hello,

I abandoned code using in this thred - it does not bode a chance of success. Instead I took code from link that @ads-ee give me in link:
https://ece-research.unm.edu/jimp/vhdl_fpgas/slides/SRAM.pdf

I made a new project in Vivado - here are sources for this new project:

1) "sram_ctrl.vhd" - the top entity:

Code:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY sram_ctrl IS
    PORT (
        clk, reset : IN std_logic;
        mem : IN std_logic;
        rw : IN std_logic;
        addr : IN std_logic_vector(17 DOWNTO 0);
        data_f2s : IN std_logic_vector(7 DOWNTO 0);
        ready : OUT std_logic;
        data_s2f_r : OUT std_logic_vector(7 DOWNTO 0);
        --data_s2f_ur : OUT std_logic_vector(7 DOWNTO 0);
        ad : OUT std_logic_vector(17 DOWNTO 0);
        we_n, oe_n : OUT std_logic;
        dio : INOUT std_logic_vector(7 DOWNTO 0);
        ce_n : OUT std_logic;
        SRAM_UB_N   : out std_logic; -- upper byte mask
        SRAM_LB_N   : out std_logic; -- lower byte mask   
        LED1, LED2 : OUT std_logic       
    );
END sram_ctrl;

ARCHITECTURE arch OF sram_ctrl IS
    TYPE state_type IS (idle, r1, r2, w1, w2);
    SIGNAL state_reg, state_next : state_type;
    SIGNAL data_f2s_reg, data_f2s_next :
    std_logic_vector(7 DOWNTO 0);
    SIGNAL data_s2f_reg, data_s2f_next :
    std_logic_vector(7 DOWNTO 0);
    SIGNAL addr_reg, addr_next :
    std_logic_vector(17 DOWNTO 0);
    SIGNAL we_buf, oe_buf, tri_buf : std_logic;
    SIGNAL we_reg, oe_reg, tri_reg : std_logic;

BEGIN
    PROCESS (clk, reset)
    BEGIN
        IF (reset = '1') THEN
            state_reg <= idle;
            addr_reg <= (OTHERS => '0');
            data_f2s_reg <= (OTHERS => '0');
            data_s2f_reg <= (OTHERS => '0');
            tri_reg <= '1';
            we_reg <= '1';
            oe_reg <= '1';
            SRAM_LB_N <= '1'; -- mask low byte
            SRAM_UB_N <= '1'; -- mask high byte
            LED1 <= '0';
            LED2 <= '0';
        ELSIF (clk'event AND clk = '1') THEN
            state_reg <= state_next;
            addr_reg <= addr_next;
            data_f2s_reg <= data_f2s_next;
            data_s2f_reg <= data_s2f_next;
            tri_reg <= tri_buf;
            we_reg <= we_buf;
            oe_reg <= oe_buf;
            SRAM_LB_N <= '0'; -- unmask low byte
            SRAM_UB_N <= '0'; -- unmask high byte
        END IF;
    END PROCESS;
    
    -- next state logic
    PROCESS (state_reg, mem, rw, dio, addr, data_f2s,
    data_f2s_reg, data_s2f_reg, addr_reg)
        BEGIN
            addr_next <= addr_reg;
            data_f2s_next <= data_f2s_reg;
            data_s2f_next <= data_s2f_reg;
            ready <= '0';
            CASE state_reg IS
                WHEN idle =>
                    IF (mem = '0') THEN
                        state_next <= idle;
                    ELSE
                        addr_next <= addr;
                        IF (rw = '0') THEN -- write
                            state_next <= w1;
                            data_f2s_next <= data_f2s;
                        ELSE
                            state_next <= r1;
                        END IF;
                    END IF;
                    ready <= '1';
                WHEN w1 =>
                    state_next <= w2;
                WHEN w2 =>
                    state_next <= idle;
                WHEN r1 =>
                    state_next <= r2;
                WHEN r2 =>
                    data_s2f_next <= dio;
                    state_next <= idle;
            END CASE;
        END PROCESS;
        -- look-ahead output logic
        PROCESS (state_next)
            BEGIN
                tri_buf <= '1';
                we_buf <= '1';
                oe_buf <= '1';
                CASE state_next IS
                    WHEN idle =>
                    WHEN w1 =>
                        tri_buf <= '0';
                        we_buf <= '0';           
                    WHEN w2 =>
                        tri_buf <= '0';
                    WHEN r1 =>
                        oe_buf <= '0';
                    WHEN r2 =>
                        oe_buf <= '0';
                END CASE;
            END PROCESS;
            
            -- to main system
            data_s2f_r <= data_s2f_reg;

            -- to SRAM
            we_n <= we_reg;
            oe_n <= oe_reg;
            ad <= addr_reg;
            -- I/O for SRAM chip
            ce_n <= '0';
            dio <= data_f2s_reg WHEN tri_reg = '0'
                   ELSE (OTHERS => 'Z');
END arch;
 

Code:
           dio <= data_f2s_reg WHEN tri_reg = '0'
                   ELSE (OTHERS => 'Z');
END arch;
This code is how you infer a tri-state in your code. It only implements the tri-state and nothing else. The dio signal is a port on the design and is only driven by this line. In all other locations it is read (on the right hand side of an assignment). You will also notice data_f2s_reg is the register used in the in the rest of the design for the dio write data.

This is the key code you were missing.

Since you are using Vivado you should elaborate your code separately and look at the schematic it can produce that will give you insights into what the tools think your code represents. If you see odd connections like the pictures I posted you will know where to look in the code for the errors.
 
this is second part of my last post:

In constraints file "sram_ctrl.xdc" I had to mix "LVCMOS33" and "LVCMOS18" standards, because I hadn't enough pins in one standard:
Code:
#set_property CFGBVS VCCO [current_design]
#set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.CONFIG.UNUSEDPIN PULLUP [current_design]

#############SPI Configurate Setting##################
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]

############## clock and reset define##################
create_clock -period 20.000 -waveform {0.000 5.000} [get_ports clk]
set_property PACKAGE_PIN H11 [get_ports clk]
set_property IOSTANDARD LVCMOS18 [get_ports clk]
###set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {CLK50MHz_IBUF}]

#Keys
set_property -dict {PACKAGE_PIN B6 IOSTANDARD LVCMOS33} [get_ports reset]
#set_property -dict {PACKAGE_PIN C5 IOSTANDARD LVCMOS33} [get_ports KEY]

#LEDs
set_property -dict {PACKAGE_PIN C4 IOSTANDARD LVCMOS33} [get_ports LED1]
set_property -dict {PACKAGE_PIN L5 IOSTANDARD LVCMOS33} [get_ports LED2]     

#addr
set_property -dict {PACKAGE_PIN M5 IOSTANDARD LVCMOS33} [get_ports {addr[17]}]
set_property -dict {PACKAGE_PIN M4 IOSTANDARD LVCMOS33} [get_ports {addr[16]}]
set_property -dict {PACKAGE_PIN M3 IOSTANDARD LVCMOS33} [get_ports {addr[15]}]
set_property -dict {PACKAGE_PIN M2 IOSTANDARD LVCMOS33} [get_ports {addr[14]}]
set_property -dict {PACKAGE_PIN M1 IOSTANDARD LVCMOS33} [get_ports {addr[13]}]
set_property -dict {PACKAGE_PIN L1 IOSTANDARD LVCMOS33} [get_ports {addr[12]}]
set_property -dict {PACKAGE_PIN L3 IOSTANDARD LVCMOS33} [get_ports {addr[11]}]
set_property -dict {PACKAGE_PIN L2 IOSTANDARD LVCMOS33} [get_ports {addr[10]}]
set_property -dict {PACKAGE_PIN K4 IOSTANDARD LVCMOS33} [get_ports {addr[9]}]
set_property -dict {PACKAGE_PIN K3 IOSTANDARD LVCMOS33} [get_ports {addr[8]}]
set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {addr[7]}]
set_property -dict {PACKAGE_PIN J3 IOSTANDARD LVCMOS33} [get_ports {addr[6]}]
set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {addr[5]}]
set_property -dict {PACKAGE_PIN J1 IOSTANDARD LVCMOS33} [get_ports {addr[4]}]
set_property -dict {PACKAGE_PIN H3 IOSTANDARD LVCMOS33} [get_ports {addr[3]}]
set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {addr[2]}]
set_property -dict {PACKAGE_PIN H1 IOSTANDARD LVCMOS33} [get_ports {addr[1]}]
set_property -dict {PACKAGE_PIN H2 IOSTANDARD LVCMOS33} [get_ports {addr[0]}]

#dio
set_property -dict {PACKAGE_PIN D2 IOSTANDARD LVCMOS33} [get_ports {dio[7]}]
set_property -dict {PACKAGE_PIN E2 IOSTANDARD LVCMOS33} [get_ports {dio[6]}]
set_property -dict {PACKAGE_PIN B2 IOSTANDARD LVCMOS33} [get_ports {dio[5]}]
set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports {dio[4]}]
set_property -dict {PACKAGE_PIN D4 IOSTANDARD LVCMOS33} [get_ports {dio[3]}]
set_property -dict {PACKAGE_PIN E4 IOSTANDARD LVCMOS33} [get_ports {dio[2]}]
set_property -dict {PACKAGE_PIN B3 IOSTANDARD LVCMOS33} [get_ports {dio[1]}]
set_property -dict {PACKAGE_PIN A2 IOSTANDARD LVCMOS33} [get_ports {dio[0]}]

#SYGNALY STERUJACE sram ic
set_property -dict {PACKAGE_PIN A4 IOSTANDARD LVCMOS33} [get_ports we_n]
set_property -dict {PACKAGE_PIN A3 IOSTANDARD LVCMOS33} [get_ports oe_n]
set_property -dict {PACKAGE_PIN C3 IOSTANDARD LVCMOS33} [get_ports ce_n]
set_property -dict {PACKAGE_PIN D3 IOSTANDARD LVCMOS33} [get_ports SRAM_UB_N]
set_property -dict {PACKAGE_PIN A5 IOSTANDARD LVCMOS33} [get_ports SRAM_LB_N]
set_property -dict {PACKAGE_PIN P12 IOSTANDARD LVCMOS18} [get_ports ready]

#data_f2s : IN std_logic_vector(7 DOWNTO 0);
set_property -dict {PACKAGE_PIN F4 IOSTANDARD LVCMOS33} [get_ports {data_f2s[7]}]
set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {data_f2s[6]}]
set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {data_f2s[5]}]
set_property -dict {PACKAGE_PIN F2 IOSTANDARD LVCMOS33} [get_ports {data_f2s[4]}]
set_property -dict {PACKAGE_PIN F1 IOSTANDARD LVCMOS33} [get_ports {data_f2s[3]}]
set_property -dict {PACKAGE_PIN G1 IOSTANDARD LVCMOS33} [get_ports {data_f2s[2]}]
set_property -dict {PACKAGE_PIN C1 IOSTANDARD LVCMOS33} [get_ports {data_f2s[1]}]
set_property -dict {PACKAGE_PIN D1 IOSTANDARD LVCMOS33} [get_ports {data_f2s[0]}]

#data_s2f_r : OUT std_logic_vector(7 DOWNTO 0);
set_property -dict {PACKAGE_PIN J11 IOSTANDARD LVCMOS18} [get_ports {data_s2f_r[7]}]
set_property -dict {PACKAGE_PIN J12 IOSTANDARD LVCMOS18} [get_ports {data_s2f_r[6]}]
set_property -dict {PACKAGE_PIN J13 IOSTANDARD LVCMOS18} [get_ports {data_s2f_r[5]}]
set_property -dict {PACKAGE_PIN J14 IOSTANDARD LVCMOS18} [get_ports {data_s2f_r[4]}]
set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS18} [get_ports {data_s2f_r[3]}]
set_property -dict {PACKAGE_PIN H14 IOSTANDARD LVCMOS18} [get_ports {data_s2f_r[2]}]
set_property -dict {PACKAGE_PIN G11 IOSTANDARD LVCMOS18} [get_ports {data_s2f_r[1]}]
set_property -dict {PACKAGE_PIN F11 IOSTANDARD LVCMOS18} [get_ports {data_s2f_r[0]}]

#------------------------------------------------------------------------------------------------

#ad
set_property -dict {PACKAGE_PIN G14 IOSTANDARD LVCMOS18} [get_ports {ad[17]}]
set_property -dict {PACKAGE_PIN F14 IOSTANDARD LVCMOS18} [get_ports {ad[16]}]
set_property -dict {PACKAGE_PIN F13 IOSTANDARD LVCMOS18} [get_ports {ad[15]}]
set_property -dict {PACKAGE_PIN E13 IOSTANDARD LVCMOS18} [get_ports {ad[14]}]
set_property -dict {PACKAGE_PIN F12 IOSTANDARD LVCMOS18} [get_ports {ad[13]}]
set_property -dict {PACKAGE_PIN E12 IOSTANDARD LVCMOS18} [get_ports {ad[12]}]
set_property -dict {PACKAGE_PIN D14 IOSTANDARD LVCMOS18} [get_ports {ad[11]}]
set_property -dict {PACKAGE_PIN C14 IOSTANDARD LVCMOS18} [get_ports {ad[10]}]
set_property -dict {PACKAGE_PIN D13 IOSTANDARD LVCMOS18} [get_ports {ad[9]}]
set_property -dict {PACKAGE_PIN H12 IOSTANDARD LVCMOS18} [get_ports {ad[8]}]
set_property -dict {PACKAGE_PIN M10 IOSTANDARD LVCMOS18} [get_ports {ad[7]}]
set_property -dict {PACKAGE_PIN P11 IOSTANDARD LVCMOS18} [get_ports {ad[6]}]
set_property -dict {PACKAGE_PIN P10 IOSTANDARD LVCMOS18} [get_ports {ad[5]}]
set_property -dict {PACKAGE_PIN N11 IOSTANDARD LVCMOS18} [get_ports {ad[4]}]
set_property -dict {PACKAGE_PIN N10 IOSTANDARD LVCMOS18} [get_ports {ad[3]}]
set_property -dict {PACKAGE_PIN M12 IOSTANDARD LVCMOS18} [get_ports {ad[2]}]
set_property -dict {PACKAGE_PIN M11 IOSTANDARD LVCMOS18} [get_ports {ad[1]}]
set_property -dict {PACKAGE_PIN P13 IOSTANDARD LVCMOS18} [get_ports {ad[0]}]

Now I haven't any synthesiss or implementation errors and resource utilization also looks OK. I attached to this post full packed project (Vivado 2018.3).

Best Regards
 

Attachments

  • SRAM_CTRL_Univ01.zip
    808.7 KB · Views: 138

I can't use Vivado right now to help you, but have you elaborated your design and schematics look similar to link from ads-ee in post #8?
Really, FPGA design is most schematics and simulations, not only errors from synthesis/impl.
Elaborated design generates much faster than synthesis, so get profit from that in every next iteration.
 
So what is the question or where is the problem if you have no Impl errors?

btw -
Code:
#SYGNALY STERUJACE sram ic
set_property -dict {PACKAGE_PIN A4 IOSTANDARD LVCMOS33} [get_ports we_n]
set_property -dict {PACKAGE_PIN A3 IOSTANDARD LVCMOS33} [get_ports oe_n]
set_property -dict {PACKAGE_PIN C3 IOSTANDARD LVCMOS33} [get_ports ce_n]
set_property -dict {PACKAGE_PIN D3 IOSTANDARD LVCMOS33} [get_ports SRAM_UB_N]
set_property -dict {PACKAGE_PIN A5 IOSTANDARD LVCMOS33} [get_ports SRAM_LB_N]
set_property -dict {PACKAGE_PIN P12 IOSTANDARD LVCMOS18} [get_ports ready]

Have you looked in to the SRAM data sheet if mixed voltage is allowed?
Do not download your bitstream in to the FPAG without verifying what voltage level is supported.
 
The RAM signals are all on 3.3V, that ready signal is NOT part of the SRAM interface it's some control signal from the FSM to report the data is ready. You can see the block diagram of the design in slide 7. Not sure what the OP is going to use to exercise the interface between the Main System and the Controller as they've put those signals on pins of the FPGA instead of connecting it to say an internal microblaze.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…