Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
10 years ago

Inferred RAM: Pass-through logic generated despite no_rw_check

Dear all,

I'm a hobbyist currently learning VHDL. My learning vehicle is a self-developed RISC-V CPU that that I develop in the Lite edition of Quartus Prime 15.1. The CPU is working fine already, but I'd like to get some rough edges smoothed out and understand what's going on.

My CPU has a unit that contains the CPU's registers. Quartus nicely infers RAM for the register file - however, it generates some pass-through logic for the particular read-during-write behavior it is seeing:

--- Quote Start ---

Warning (276020): Inferred RAM node "cpu_toplevel:cpu_instance|registers:reg_instance|regs_rtl_0" from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design.

--- Quote End ---

The code:


library IEEE;
use IEEE.std_logic_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library work;
use work.constants.all;
entity registers is
    Port(
        I_clk: in std_logic;
        I_en: in std_logic;
        I_op: in std_logic_vector(1 downto 0);
        I_selS1: in std_logic_vector(4 downto 0);
        I_selS2: in std_logic_vector(4 downto 0);
        I_selD: in std_logic_vector(4 downto 0);
        I_dataAlu: in std_logic_vector(XLEN-1 downto 0);
        I_dataMem: in std_logic_vector(XLEN-1 downto 0);
        O_dataS1: out std_logic_vector(XLEN-1 downto 0);
        O_dataS2: out std_logic_vector(XLEN-1 downto 0)
    );
end registers;
architecture Behavioral of registers is
    type store_t is array(1 to 31) of std_logic_vector(XLEN-1 downto 0);
    signal regs: store_t := (others => X"00000000");
    attribute ramstyle : string;
    attribute ramstyle of regs : signal is "no_rw_check"; -- why does Quartus still add pass-through logic?
begin
    process(I_clk)
    begin
        if rising_edge(I_clk) and I_en = '1' then
            -- TODO: find out why synthesis sees read-during-write behavior
    
            case I_op is
                when REGOP_READ =>
                    if I_selS1 = R0 then
                        O_dataS1 <= X"00000000";
                    else
                        O_dataS1 <= regs(to_integer(unsigned(I_selS1)));
                    end if;
                    if I_selS2 = R0 then
                        O_dataS2 <= X"00000000";
                    else
                        O_dataS2 <= regs(to_integer(unsigned(I_selS2)));
                    end if;
                
                
                when REGOP_WRITE_ALU =>
                    if I_selD /= R0 then
                        regs(to_integer(unsigned(I_selD))) <= I_dataAlu;
                    end if;
                
                
                when REGOP_WRITE_MEM =>
                    if I_selD /= R0 then
                        regs(to_integer(unsigned(I_selD))) <= I_dataMem;
                    end if;
                
                when others =>
                    null;
            
            end case;
    
        end if;
    end process;
end Behavioral;

(XLEN is a constant that denotes architecture bit width, in this case the value is 32. Register 0 is always zero, thus there are registers 1 to 31.)

The synthesized design works fine in both simulation and on FPGA (Cyclone IV on a DE0 Nano board), but I currently do not understand following issues:

  • Why does synthesis see read-during-write behavior? As far as I can see (and as far as is intended) there will either be two read accesses (when reading register values) or one write access (when storing results from the ALU or from memory) - but not both in the same cycle. I assume that I misunderstand VHDL semantics in this regard.

  • The pass-through logic is generated despite the "no_rw_check" ramstyle attribute. My understanding is that this attribute is supposed to tell synthesis not to synthesize additional logic to implement the design's read-during-write behavior. The attribute itself seems to be attached properly, for instance I can successfully tell synthesis to generate the registers in logic instead of utilizing ram blocks.

I would greatly appreciate hints to improve my understanding of what's going on there.

Best regards,

Maik

14 Replies