earlz Posted May 2, 2012 Report Share Posted May 2, 2012 Hello, I'm trying to synthesize a single port RAM block that has 2 write-enable bits. This is so that I can choose to either write 16 bits or 8 bits at a time. My VHDL code is as follows: library IEEE; use IEEE.STD_LOGIC_1164.ALL; use ieee.std_logic_arith.all; use IEEE.NUMERIC_STD.ALL; use ieee.std_logic_unsigned.all; entity blockram is port( Address: in std_logic_vector(7 downto 0); --memory address WriteEnable: in std_logic_vector(1 downto 0); --write 1 byte at a time option Enable: in std_logic; Clock: in std_logic; DataIn: in std_logic_vector(15 downto 0); DataOut: out std_logic_vector(15 downto 0) ); end blockram; architecture Behavioral of blockram is type ram_type is array (255 downto 0) of std_logic_vector (15 downto 0); signal RAM: ram_type; attribute ram_style: string; attribute ram_style of RAM: signal is "block"; signal di0, di1, do0, do1: std_logic_vector(7 downto 0); --data inputs and outputs for byte-enable begin process (WriteEnable,DataIn) begin if WriteEnable(0) = '1' then di0 <= DataIn(7 downto 0); else di0 <= RAM(conv_integer(Address))(7 downto 0); do0 <= RAM(conv_integer(Address))(7 downto 0); end if; if WriteEnable(1)= '1' then di1 <= DataIn(15 downto 8); else di1 <= RAM(conv_integer(Address))(15 downto 8); do1 <= RAM(conv_integer(Address))(15 downto 8); end if; end process; process (Clock) begin if rising_edge(Clock) then if Enable = '1' then DataOut <= do1 & do0; RAM(conv_integer(Address)) <= di1 & di0; end if; end if; end process; end Behavioral; When I try synthesizing this however I get an error/warning: "Cannot use block RAM resources for signal <Mram_RAM>. Please check that the RAM contents is read synchronously." Am I doing something wrong? I'm trying to follow the template provided inside WebPack, but it always synthesizes to use LUTs instead of RAM. Does the Spartan3E 250K RAM blocks support this kind of thing? Link to comment Share on other sites More sharing options...
Adrian Posted May 2, 2012 Report Share Posted May 2, 2012 Hello, I'm trying to synthesize a single port RAM block that has 2 write-enable bits. This is so that I can choose to either write 16 bits or 8 bits at a time. My VHDL code is as follows: library IEEE; use IEEE.STD_LOGIC_1164.ALL; use ieee.std_logic_arith.all; use IEEE.NUMERIC_STD.ALL; use ieee.std_logic_unsigned.all; entity blockram is port( Address: in std_logic_vector(7 downto 0); --memory address WriteEnable: in std_logic_vector(1 downto 0); --write 1 byte at a time option Enable: in std_logic; Clock: in std_logic; DataIn: in std_logic_vector(15 downto 0); DataOut: out std_logic_vector(15 downto 0) ); end blockram; architecture Behavioral of blockram is type ram_type is array (255 downto 0) of std_logic_vector (15 downto 0); signal RAM: ram_type; attribute ram_style: string; attribute ram_style of RAM: signal is "block"; signal di0, di1, do0, do1: std_logic_vector(7 downto 0); --data inputs and outputs for byte-enable begin process (WriteEnable,DataIn) begin if WriteEnable(0) = '1' then di0 <= DataIn(7 downto 0); else di0 <= RAM(conv_integer(Address))(7 downto 0); do0 <= RAM(conv_integer(Address))(7 downto 0); end if; if WriteEnable(1)= '1' then di1 <= DataIn(15 downto; else di1 <= RAM(conv_integer(Address))(15 downto; do1 <= RAM(conv_integer(Address))(15 downto; end if; end process; process (Clock) begin if rising_edge(Clock) then if Enable = '1' then DataOut <= do1 & do0; RAM(conv_integer(Address)) <= di1 & di0; end if; end if; end process; end Behavioral; When I try synthesizing this however I get an error/warning: "Cannot use block RAM resources for signal <Mram_RAM>. Please check that the RAM contents is read synchronously." Am I doing something wrong? I'm trying to follow the template provided inside WebPack, but it always synthesizes to use LUTs instead of RAM. Does the Spartan3E 250K RAM blocks support this kind of thing? Hi Earlz, Your process that reads the BRAM values isn't reading them synchronously, but rather concurrently; you want to read data out of the BRAM in a process that only has the clock in its sensitivity list. Thats what the error is warning you about. More importantly, though, you can't implement byte enable natively in BRAMS on a Virtex 3e, as far as I can tell; from the Xilinx BRAM Data Sheet: RAMB primitive in architectures prior to Virtex-4 only have a single write enable per port. Thus if byte-write enable is required on a 32 bit data port (C_NUM_WE=4), these architectures will use a minimum of 4 BRAM primitives. If you can deal with a few cycle latency between reads and writes, you can implement byte-enable in logic around the BRAM, but it would really matter on your application design - let us know more details, and we can try and help you with a good fix. -Adrian Link to comment Share on other sites More sharing options...
Adrian Posted May 2, 2012 Report Share Posted May 2, 2012 Additionally, looking at the code again, do0 and do1 are both going to implemented as latches - they aren't set on every branch of the conditions. You are going to want to set them to some value when WriteEnable(0) and WriteEnable(1) are true, not just when they are false. Link to comment Share on other sites More sharing options...
earlz Posted May 2, 2012 Author Report Share Posted May 2, 2012 I've changed my code quite a bit and no warning when synthesizing now I've been trying at this all day only to discover I'm trying to implement the impossible Anyway, I really can't have the latency in my application (a tiny 8-bit CPU) so I decided to implement it as 2 banks of 8-bit block RAM and writing to them selectively on WriteEnable(x). I believe this is the best solution in my case as I don't plan on using many of my block RAMs anyway (and 2 out of 12 isn't too much in my eyes) Edit: Also, just for reference, here is my working code, though I plan on changing how DataOut synchronizes with Address and WriteEnables entity blockram is port( Address: in std_logic_vector(7 downto 0); --memory address WriteEnable: in std_logic_vector(1 downto 0); --write 1 byte at a time option Enable: in std_logic; Clock: in std_logic; DataIn: in std_logic_vector(15 downto 0); DataOut: out std_logic_vector(15 downto 0) ); end blockram; architecture Behavioral of blockram is type ram_type is array (255 downto 0) of std_logic_vector (7 downto 0); signal RAM0: ram_type; --Spartan 3Es don't natively support byte-wide write enables, so we'll just emulate it with 2 banks of RAM signal RAM1: ram_type; signal di0, di1: std_logic_vector(7 downto 0); signal do : std_logic_vector(15 downto 0); begin di0 <= DataIn(7 downto 0) when WriteEnable(0)='1' else do(7 downto 0); di1 <= DataIn(15 downto 8) when WriteEnable(1)='1' else do(15 downto 8); process (Clock) begin if rising_edge(Clock) then if Enable = '1' then if WriteEnable(0)='1' then RAM0(conv_integer(Address)) <= di0; else do(7 downto 0) <= RAM0(conv_integer(Address)) ; end if; if WriteEnable(1)='1' then RAM1(conv_integer(Address)) <= di1; else do(15 downto 8) <= RAM1(conv_integer(Address)); end if; end if; end if; end process; DataOut <= do; end Behavioral; Link to comment Share on other sites More sharing options...
Adrian Posted May 2, 2012 Report Share Posted May 2, 2012 begin di0 <= DataIn(7 downto 0) when WriteEnable(0)='1' else do(7 downto 0); di1 <= DataIn(15 downto when WriteEnable(1)='1' else do(15 downto; process (Clock) begin if rising_edge(Clock) then if Enable = '1' then if WriteEnable(0)='1' then RAM0(conv_integer(Address)) <= di0; else do(7 downto 0) <= RAM0(conv_integer(Address)) ; end if; if WriteEnable(1)='1' then RAM1(conv_integer(Address)) <= di1; else do(15 downto <= RAM1(conv_integer(Address)); end if; end if; end if; end process; DataOut <= do; end Behavioral; The following seems a little clearer, at least to me: begin process (Clock) begin if rising_edge(Clock) then if Enable = '1' then if WriteEnable(0)='1' then RAM0(conv_integer(Address)) <= DataIn(7 downto 0); else DataOut(7 downto 0) <= RAM0(conv_integer(Address)) ; end if; if WriteEnable(1)='1' then RAM1(conv_integer(Address)) <= DataIn(15 downto 8); else DataOut(15 downto 8) <= RAM1(conv_integer(Address)); end if; end if; end if; end process; end Behavioral; Link to comment Share on other sites More sharing options...
Jack Gassett Posted May 3, 2012 Report Share Posted May 3, 2012 earlz, It might be easier to use the memory wizard to generate a memory block for you at first. To use the memory wizard: Add "New Source" to your projectChoose "IP (CORE Generator & Architecture Wizard)Choose "Memories & Storage Elements\RAMs & ROMs\Block Memory Generator"That will get you started with the wizard. Jack. Link to comment Share on other sites More sharing options...
hamster Posted May 13, 2012 Report Share Posted May 13, 2012 You can construct something that looks like a 16 bit RAM with byte enable using the dual-port feature of Block RAM. Create a dual-port block ram, with a data width of 8 bits. Use the "Port A" to handle the lower byte, and "Port B" for the upper byte. Set the address for port A to be 'your_address & "0''. Set the address for port B to be 'your_address & "1"'. Concatenate the data outputs for portA and portB to form your 16 bit "dout" word. Assign the lower and upper bytes of "din" (your data to be written) to the DIN ports of Port A and Port B. Set the "WE" of Port A to be "WriteEnable and LowerByteEnable", and use "WriteEnable and UpperByteEnable" for the "WE" on Port B. Link to comment Share on other sites More sharing options...
earlz Posted May 14, 2012 Author Report Share Posted May 14, 2012 earlz, It might be easier to use the memory wizard to generate a memory block for you at first. To use the memory wizard: Add "New Source" to your projectChoose "IP (CORE Generator & Architecture Wizard)Choose "Memories & Storage Elements\RAMs & ROMs\Block Memory Generator"That will get you started with the wizard. Jack. But then simulation without Xilinx tools is impossible. MY workflow is like this: 1. Write VHDL code in Kate 2. Simulate VHDL code using ghdl and gtkwave 3. Repeat ... And then every once in a while I'll put all of my code into xilinx tools so I can test that they synthesize correctly. I find the Xilinx tools extremely cumbersome so this is why I'd prefer not to use them when I don't have to You can construct something that looks like a 16 bit RAM with byte enable using the dual-port feature of Block RAM. Create a dual-port block ram, with a data width of 8 bits. Use the "Port A" to handle the lower byte, and "Port B" for the upper byte. Set the address for port A to be 'your_address & "0''. Set the address for port B to be 'your_address & "1"'. Concatenate the data outputs for portA and portB to form your 16 bit "dout" word. Assign the lower and upper bytes of "din" (your data to be written) to the DIN ports of Port A and Port B. Set the "WE" of Port A to be "WriteEnable and LowerByteEnable", and use "WriteEnable and UpperByteEnable" for the "WE" on Port B. I tried to get something like this to work, but I never could get XST to synthesize it correctly, so I gave up and instead used 2 8-bit block RAMs Link to comment Share on other sites More sharing options...
Adrian Posted May 15, 2012 Report Share Posted May 15, 2012 I tried to get something like this to work, but I never could get XST to synthesize it correctly, so I gave up and instead used 2 8-bit block RAMs Currently, as far as I know, you cannot infer the following constructs with BRAMs - dual clock domains, byte enables, and different word sizes between reads and writes. If you were trying to infer a BRAM with a byte enable, the synthesis tool may have been unable to construct it properly in order to replace it with a BRAM primitive. Have you thought about have a different file for simulation / testing then you have for synthesis / P&R? Test your code with your inferred BRAM with byte enable, then switch over to using a primitive instantiation / pcore when you actually need to synthesis. I agree with you about ISE, by the way, it is quite clunky. Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.