Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

memory_libmap: look for ram_style attributes on surrounding signals #4008

Merged
merged 4 commits into from
Nov 6, 2023

Conversation

nakengelhardt
Copy link
Member

@nakengelhardt nakengelhardt commented Oct 19, 2023

One generally accepted way to describe ROMs is through a case statement:

module rom(input clk, input [2:0] addr, 
	// ram style on output register is not respected but is the norm:
	(* ram_style = "block" *)
	output reg [7:0] data);

always @(posedge clk) begin
	// ram style on case statement is respected but not the norm:
	// (* ram_style = "block" *)
	case (addr)
		3'b000: data <= 8'h12;
		3'b001: data <= 8'hAB;
		3'b010: data <= 8'h42;
		3'b011: data <= 8'h23;
		3'b100: data <= 8'h66;
		3'b101: data <= 8'hC0;
		3'b110: data <= 8'h3F;
		3'b111: data <= 8'h95;
	endcase
end

endmodule

(See https://docs.xilinx.com/r/en-US/ug901-vivado-synthesis/ROM-Using-Block-RAM-Resources-Verilog for a vendor recommending this style.)

Or the corresponding VHDL description:

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity rom_example is
	port (
		clk : in std_logic;
		addr : in std_logic_vector(2 downto 0);
		data : out std_logic_vector (7 downto 0)
	);
end entity rom_example;

architecture rtl of rom_example is
	attribute rom_style : string;
	attribute rom_style of data : signal is "block";
begin
	
	p_rom : process(clk)
	begin
		if rising_edge(clk) then
			case addr is
				when "000" => data <= X"12";
				when "001" => data <= X"AB";
				when "010" => data <= X"42";
				when "011" => data <= X"23";
				when "100" => data <= X"66";
				when "101" => data <= X"C0";
				when "110" => data <= X"3F";
				when others => data <= X"95";
			end case;
		end if;
	end process p_rom;
	
end architecture rtl;

(Recommended by another vendor: https://www.intel.com/content/www/us/en/docs/programmable/683082/23-1/inferring-rom-functions-from-hdl-code.html)

In this case, the intuitive place to put the ram_style attribute would be on the output register. Verilog is flexible enough to allow attributes on the case statement, which does get successfully handed down through proc_rom or memory_bmux2rom (for read_verilog and verific respectively) to the inferred $mem_v2 cell, but VHDL only allows attributes on named objects so the output signal is the only possible place to put the attribute in the VHDL description. (This is mostly not an issue for RAM inference since there is always an array declaration that is the more natural place to put the attribute, but it should still be supported to put it on the output signal IMO.)

This PR makes memory_libmap search for attributes on the data and address wires if they aren't found on the memory itself. (The implementation is a bit ugly, happy to take suggestions for improvement.)

It also adds (* no_ram *) as a synonym for (* ram_style = "logic" *) since I happened to come across it while browsing vendor documentation.

Currently this will fail the verific tests because verific doesn't import the attributes on port signals; don't merge until a fix for that is in. (@mmicko can you have a look at those test cases?)

@nakengelhardt nakengelhardt merged commit 93a426c into YosysHQ:master Nov 6, 2023
15 checks passed
@nakengelhardt nakengelhardt deleted the mem_libmap_data_attr branch November 6, 2023 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant