/// <summary> /// Gets the instantiation block for a single blockram instance. /// </summary> /// <returns>The instantiation region.</returns> /// <param name="config">The configuration to generate the instantiation for.</param> /// <param name="instancename">The name of the encapsulating instance.</param> /// <param name="initialvalue">The initial value for the output</param> /// <param name="index">The instance index to use, or negative for no indexing</param> private string GetInstantiationRegion(BlockRamConfig config, string instancename, string initialvalue, IEnumerable <string> memdatalines, IEnumerable <string> pardatalines, int index = -1) { var memlines = string.Join( "," + Environment.NewLine, Enumerable.Range(0, int.MaxValue) .Zip( memdatalines, (a, b) => string.Format(" INIT_{0:X2} => X\"{1}\"", a, b) ) ); var paritylines = string.Join( "," + Environment.NewLine, Enumerable.Range(0, int.MaxValue) .Zip( pardatalines, (a, b) => string.Format(" INITP_{0:X2} => X\"{1}\"", a, b) ) ); var index_suffix = index < 0 ? string.Empty : $"_{index}"; return ($@" {instancename}_inst{index_suffix} : BRAM_SINGLE_MACRO generic map ( BRAM_SIZE => ""{(config.use36k ? "36Kb" : "18Kb")}"", -- Target BRAM, ""18Kb"" or ""36Kb"" DEVICE => ""{ config.targetdevice }"", --Target device: ""VIRTEX5"", ""VIRTEX6"", ""7SERIES"", ""SPARTAN6"" DO_REG => 0, --Optional output register(0 or 1) WRITE_WIDTH => { config.datawidth }, --Valid values are 1 - 72(37 - 72 only valid when BRAM_SIZE = ""36Kb"") READ_WIDTH => { config.datawidth }, --Valid values are 1 - 72(37 - 72 only valid when BRAM_SIZE = ""36Kb"") INIT_FILE => ""NONE"", SRVAL => X""{ initialvalue}"", --Set / Reset value for port output WRITE_MODE => ""READ_FIRST"", --Specify ""READ_FIRST"" for same clock or synchronous clocks -- Specify ""WRITE_FIRST"" for asynchrononous clocks on ports -- The following INIT_xx declarations specify the initial contents of the RAM { memlines }, -- The next set of INITP_xx are for the parity bits { paritylines }, INIT => X""{ initialvalue}"" --Initial values on output port ) port map ( DO => DO_internal{index_suffix}, -- Output read data port, width defined by READ_WIDTH parameter DI => DI_internal{index_suffix}, -- Input write data port, width defined by WRITE_WIDTH parameter ADDR => ADDR_internal{index_suffix}, -- Input address, width defined by read/write port depth CLK => CLK, -- 1-bit input clock EN => EN_internal{index_suffix}, -- 1-bit input enable REGCE => '0', -- 1-bit input read output register enable RST => RST, -- 1-bit input reset WE => WE_internal{index_suffix} -- Input write enable, width defined by write port depth ); -- End of BRAM_SINGLE_MACRO instantiation "); }
/// <summary> /// Gets a set of signals for communicating with a single blockram instance /// </summary> /// <returns>The signal region.</returns> /// <param name="config">The configuration to generate the signals for.</param> /// <param name="index">The instance index to use, or negative for no indexing</param> private string GetSignalRegion(BlockRamConfig config, int index = -1, int overrideAddrWidth = -1) { var index_suffix = index < 0 ? string.Empty : $"_{index}"; return($@" signal EN_internal{index_suffix}: std_logic; signal WE_internal{index_suffix}: std_logic_vector({config.wewidth - 1} downto 0); signal DI_internal{index_suffix}: std_logic_vector({config.datawidth - 1} downto 0); signal DO_internal{index_suffix}: std_logic_vector({config.datawidth - 1} downto 0); signal ADDR_internal{index_suffix}: std_logic_vector({(overrideAddrWidth <= 0 ? (config.realaddrwidth - 1) : (overrideAddrWidth - 1))} downto 0); "); }
public string BodyRegion(RenderStateProcess renderer, int indentation) { var initialdata = (Array)renderer.Process.SharedVariables.First(x => x.Name == "m_memory").DefaultValue; var size = initialdata.Length; var datawidth = VHDLHelper.GetBitWidthFromType(initialdata.GetType().GetElementType()); var resetinitial = renderer.Process.LocalBusNames.Keys.Where(x => x.SourceType.Name == nameof(SME.Components.SinglePortMemory <int> .IReadResult)).SelectMany(x => x.Signals).First().DefaultValue; var initialvalue = VHDLHelper.GetDataBitString(initialdata.GetType().GetElementType(), resetinitial, datawidth); var itemsPr18k = ((18 * 1024) + (datawidth - 1)) / datawidth; var in18kBlocks = (size + (itemsPr18k - 1)) / itemsPr18k; var fullAddressWidth = (int)Math.Ceiling(Math.Log(size, 2)); var self = renderer.Process; var outbus = self.OutputBusses.First(); var inbus = self.InputBusses.First(); string signaltemplate; string instancetemplate; string gluetemplate; string clocktemplate; int targetwidth; // Single 18k or single 36k item instantiation if (in18kBlocks <= 2) { var config = new BlockRamConfig(renderer, datawidth, datawidth * size, false); signaltemplate = GetSignalRegion(config, -1); var initlines = VHDLHelper.SplitDataBitStringToMemInit( VHDLHelper.GetDataBitStrings(initialdata), config.datawidth, config.paritybits ); targetwidth = config.realaddrwidth; instancetemplate = GetInstantiationRegion(config, renderer.Process.InstanceName, initialvalue, initlines.Item1, initlines.Item2, -1); gluetemplate = string.Empty; clocktemplate = string.Empty; } // Multi-unit instantiation else { var addrWidth = (int)Math.Floor(Math.Log(((36 * 1024) + (datawidth - 1)) / datawidth, 2)); var itemsPrBlock = (int)Math.Pow(2, addrWidth); var blocks = (size + (itemsPrBlock - 1)) / itemsPrBlock; var sbsignals = new System.Text.StringBuilder(); var sbinstances = new System.Text.StringBuilder(); var sbglue = new System.Text.StringBuilder(); var itemConfig = new BlockRamConfig(renderer, datawidth, itemsPrBlock * datawidth, true); sbsignals.Append(GetSignalRegion(itemConfig, -1, fullAddressWidth)); sbsignals.AppendLine($"signal ADDR_READ_internal: std_logic_vector({fullAddressWidth - 1} downto 0);"); for (var i = 0; i < blocks; i++) { var config = new BlockRamConfig(renderer, datawidth, itemsPrBlock * datawidth, false); sbsignals.Append(GetSignalRegion(config, i)); var initlines = VHDLHelper.SplitDataBitStringToMemInit( VHDLHelper.GetDataBitStrings(initialdata, i * itemsPrBlock, itemsPrBlock), config.datawidth, config.paritybits ); sbinstances.Append(GetInstantiationRegion(config, renderer.Process.InstanceName, initialvalue, initlines.Item1, initlines.Item2, i)); var indexAsBitString = VHDLHelper.GetDataBitString(i, fullAddressWidth - addrWidth); indexAsBitString = indexAsBitString.Substring(indexAsBitString.Length - (fullAddressWidth - addrWidth)); sbglue.AppendLine($@" EN_internal_{i} <= '1' when (EN_internal = '1') and (ADDR_internal({fullAddressWidth - 1} downto {addrWidth}) = ""{indexAsBitString}"") else '0'; WE_internal_{i} <= WE_internal; DI_internal_{i} <= DI_internal; ADDR_internal_{i} <= ADDR_internal({addrWidth - 1} downto 0); "); } // Create the output driver sbglue.AppendLine(GenerateOutputSelector(self.InstanceName, blocks, fullAddressWidth, addrWidth)); targetwidth = fullAddressWidth; signaltemplate = sbsignals.ToString(); instancetemplate = sbinstances.ToString(); gluetemplate = sbglue.ToString(); clocktemplate = "ADDR_READ_internal <= ADDR_internal;"; } var template = $@" {signaltemplate} begin {instancetemplate} {self.InstanceName}_Helper: process(RST,CLK, RDY) begin if RST = '1' then FIN <= '0'; elsif rising_edge(CLK) then FIN <= not RDY; {clocktemplate} end if; end process; {gluetemplate} EN_internal <= ENB and {Naming.ToValidName(renderer.Parent.GetLocalBusName(inbus, self) + "_" + nameof(SME.Components.SinglePortMemory<int>.IControl.Enabled)) }; WE_internal <= (others => EN_internal and {Naming.ToValidName(renderer.Parent.GetLocalBusName(inbus, self) + "_" + nameof(SME.Components.SinglePortMemory<int>.IControl.IsWriting)) }); DI_internal <= std_logic_vector({ Naming.ToValidName(renderer.Parent.GetLocalBusName(inbus, self) + "_" + nameof(SME.Components.SinglePortMemory<int>.IControl.Data)) }); ADDR_internal <= std_logic_vector(resize(unsigned({ Naming.ToValidName(renderer.Parent.GetLocalBusName(inbus, self) + "_" + nameof(SME.Components.SinglePortMemory<int>.IControl.Address)) }), {targetwidth})); { Naming.ToValidName(renderer.Parent.GetLocalBusName(outbus, self) + "_" + nameof(SME.Components.SinglePortMemory<int>.IReadResult.Data)) } <= {renderer.Parent.VHDLWrappedTypeName(outbus.Signals.First())}(DO_internal); "; return(VHDLHelper.ReIndentTemplate(template, indentation)); }
/// <summary> /// Gets the instantiation block for a single blockram instance. /// </summary> /// <returns>The instantiation region.</returns> /// <param name="config">The configuration to generate the instantiation for.</param> /// <param name="instancename">The name of the encapsulating instance.</param> /// <param name="initialvalue">The initial value for the output</param> /// <param name="index">The instance index to use, or negative for no indexing</param> private string GetInstantiationRegion(BlockRamConfig config, string instancename, string initialvalue, IEnumerable <string> memdatalines, IEnumerable <string> pardatalines, int index = -1) { var memlines = string.Join( "," + Environment.NewLine, Enumerable.Range(0, int.MaxValue) .Zip( memdatalines, (a, b) => string.Format(" INIT_{0:X2} => X\"{1}\"", a, b) ) ); var paritylines = string.Join( "," + Environment.NewLine, Enumerable.Range(0, int.MaxValue) .Zip( pardatalines, (a, b) => string.Format(" INITP_{0:X2} => X\"{1}\"", a, b) ) ); var index_suffix = index < 0 ? string.Empty : $"_{index}"; return ($@" {instancename}_inst{index_suffix} : BRAM_TDP_MACRO generic map ( BRAM_SIZE => ""{(config.use36k ? "36Kb" : "18Kb")}"", -- Target BRAM, ""18Kb"" or ""36Kb"" DEVICE => ""{ config.targetdevice }"", --Target device: ""VIRTEX5"", ""VIRTEX6"", ""7SERIES"", ""SPARTAN6"" DOA_REG => 0, --Optional port A output register(0 or 1) DOB_REG => 0, --Optional port B output register(0 or 1) INIT_FILE => ""NONE"", READ_WIDTH_A => { config.datawidth }, -- Valid values are 1 - 36(19 - 36 only valid when BRAM_SIZE = ""36Kb"") READ_WIDTH_B => { config.datawidth }, -- Valid values are 1 - 36(19 - 36 only valid when BRAM_SIZE = ""36Kb"") SIM_COLLISION_CHECK => ""GENERATE_X_ONLY"", --Collision check enable ""ALL"", ""WARNING_ONLY"", --""GENERATE_X_ONLY"" or ""NONE"" SRVAL_A => X""{ initialvalue}"", --Set / Reset value for A port output SRVAL_B => X""{ initialvalue}"", --Set / Reset value for B port output WRITE_MODE_A => ""READ_FIRST"", -- ""WRITE_FIRST"", ""READ_FIRST"" or ""NO_CHANGE"" WRITE_MODE_B => ""READ_FIRST"", -- ""WRITE_FIRST"", ""READ_FIRST"" or ""NO_CHANGE"" WRITE_WIDTH_A => { config.datawidth }, -- Valid values are 1 - 36(19 - 36 only valid when BRAM_SIZE = ""36Kb"") WRITE_WIDTH_B => { config.datawidth }, -- Valid values are 1 - 36(19 - 36 only valid when BRAM_SIZE = ""36Kb"") -- The following INIT_xx declarations specify the initial contents of the RAM { memlines }, -- The next set of INITP_xx are for the parity bits { paritylines }, INIT_A => X""{ initialvalue}"", --Initial values on A output port INIT_B => X""{ initialvalue}"" --Initial values on B output port ) port map ( DOA => DOA_internal{index_suffix}, -- Output port-A, width defined by READ_WIDTH_A parameter DOB => DOB_internal{index_suffix}, -- Output port-B, width defined by READ_WIDTH_B parameter ADDRA => ADDRA_internal{index_suffix}, -- Input port-A address, width defined by Port A depth ADDRB => ADDRB_internal{index_suffix}, -- Input port-B address, width defined by Port B depth CLKA => CLK, -- 1-bit input port-A clock CLKB => CLK, -- 1-bit input port-B clock DIA => DIA_internal{index_suffix}, -- Input port-A data, width defined by WRITE_WIDTH_A parameter DIB => DIB_internal{index_suffix}, -- Input port-B data, width defined by WRITE_WIDTH_B parameter ENA => ENA_internal{index_suffix}, -- 1-bit input port-A enable ENB => ENB_internal{index_suffix}, -- 1-bit input port-B enable REGCEA => '0', -- 1-bit input port-A register enable REGCEB => '0', -- 1-bit input port-B register enable RSTA => RST, -- 1-bit input port-A reset RSTB => RST, -- 1-bit input port-B reset WEA => WEA_internal{index_suffix}, -- Input port-A write enable, width defined by port A depth WEB => WEB_internal{index_suffix} -- Input port-B write enable, width defined by port B depth ); -- End of BRAM_TDP_MACRO_inst instantiation "); }