I have created a 2D RAM block, it is an array of 32 bit std_logic_vectors:
subtype TEST_MEM_DATA_WORD is std_logic_vector(31 downto 0);
type TEST_MEM_DATA_MEM_ARRAY is array (natural range <>) of TEST_MEM_DATA_WORD;
signal TEST_DATA_MEM : TEST_MEM_DATA_MEM_ARRAY (63 downto 0);
Here is the process that is used to read and write it:
TEST_DATA_MEM_PROC: process(CLK) is
variable address_int: natural;
begin
if rising_edge(CLK) then
if RESET = '0' then
TEST_DATA_MEM <= (others=>(others=>'0'));
TEST_MEMORY_RDATA_OUT <= (others=>'0');
address_int := 0;
else
address_int := to_integer(unsigned(TEST_MEMORY_ADDR_IN));
if TEST_MEMORY_WR_IN = '1' then
TEST_DATA_MEM (address_int) <= TEST_MEMORY_WDATA_IN;
end if;
if TEST_MEMORY_RD_IN = '1' then
TEST_MEMORY_RDATA_OUT <= TEST_DATA_MEM (address_int);
end if;
end if;
end if;
end process;
I want to achieve a scenario where the few address locations of the TEST_DATA_MEM have constant values assigned to them. We are able to read these locations but not able to write these locations. How should this process be changed to achieve this end? There are certainly multiple ways but I want to know the proper way. I think this would be where no registers would have to be synthesized since the value shall remain constant forever.
Putting constant assignment outside the process will clash since there will be 2 drivers into the process. Putting assignment at end of the clocked process is one way to do this. However, I suspect that this shall infer registers since the constant values shall get assigned on the first rising edge of clock and not from time zero.
Using an if statement to check the address value before writing into the memory as another way to ensure that only the value assigned in the process remains. However, as per syntax of VHDL and the typical synthesis tool rules, there must be a way to achieve this without involving an if statement that checks the address value when TEST_MEMORY_WR_IN is '1'.
-
\$\begingroup\$ I don't know if there's a special VHDL feature for this. At my company where we use Verilog we have a separate Python script to auto-generate our register map source files, with generated address-by-address if statements and concatenations as needed. It doesn't synthesize to an optimized RAM cell, just a bunch of registers though. \$\endgroup\$Justin– Justin2020年09月17日 20:42:56 +00:00Commented Sep 17, 2020 at 20:42
-
\$\begingroup\$ This memory shall have to synthesized using logic cells and not BRAM \$\endgroup\$gyuunyuu– gyuunyuu2020年09月17日 20:49:14 +00:00Commented Sep 17, 2020 at 20:49
-
1\$\begingroup\$ TEST_MEM_DATA_MEM_ARRAY is a single dimensional array it has only one index. Either qualifying writes as you indicate or assigning constant values to the output for specific addresses will prevent locations from being both written and read allowing optimization to remove the constants registers. The latter method is vendor agnostic, diverting some inputs to the read output multiplexer. \$\endgroup\$user8352– user83522020年09月17日 21:30:49 +00:00Commented Sep 17, 2020 at 21:30
1 Answer 1
Instead of special-casing the writes, do it on the reads. The optimizer will automatically delete any registers that are written but never read.
if TEST_MEMORY_RD_IN = '1' then
case address_int is
when special_address_a => TEST_MEMORY_RDATA_OUT <= special_data_a;
when special_address_b => TEST_MEMORY_RDATA_OUT <= special_data_b;
when others => TEST_MEMORY_RDATA_OUT <= TEST_DATA_MEM (address_int);
end case;
end if;