public SinglePortBlockRamTester(int memsize, bool random = false, int seed = 42) { var rndbuf = new byte[8]; var rnd = new Random(seed); m_initial = new TData[memsize]; m_rnd = new TData[m_initial.Length]; for (var i = 0; i < m_initial.Length; i++) { rnd.NextBytes(rndbuf); m_rnd[i] = VHDLHelper.CreateIntType <TData>(BitConverter.ToUInt64(rndbuf, 0)); if (random) { rnd.NextBytes(rndbuf); m_initial[i] = VHDLHelper.CreateIntType <TData>(BitConverter.ToUInt64(rndbuf, 0)); } else { m_initial[i] = VHDLHelper.CreateIntType <TData>((ulong)i); } } m_bram = new SME.Components.SinglePortMemory <TData>(memsize, m_initial); m_control = m_bram.Control; m_rddata = m_bram.ReadResult; Simulation.Current.AddTopLevelInputs(m_control); Simulation.Current.AddTopLevelOutputs(m_rddata); }
/// <summary> /// Initializes a new instance of the <see cref="T:SME.VHDL.Components.TrueDualPortMemory`2"/> class. /// </summary> /// <param name="initial">The initial memory contents</param> /// <param name="initialvalue">The initial output value on the output port</param> /// <param name="elementcount">The number of elements to use. This parameter is ignored unless the <typeparamref name="TAddress"/> parameter is an <see cref="int"/></param> public TrueDualPortMemory(TData[] initial = null, TData initialvalue = default(TData), int elementcount = -1) : base() { var dataWidth = VHDLHelper.GetBitWidthFromType(typeof(TData)); int addrWidth; if (typeof(TAddress) == typeof(int)) { if (elementcount <= 0) { throw new ArgumentOutOfRangeException(nameof(elementcount), elementcount, $"When using an {typeof(int)} address, the {nameof(elementcount)} parameter must be set"); } addrWidth = (int)Math.Ceiling(Math.Log(elementcount, 2)); } else { addrWidth = VHDLHelper.GetBitWidthFromType(typeof(TAddress)); } DataWidthA = dataWidth; AddressWidthA = addrWidth; DataWidthB = dataWidth; AddressWidthB = addrWidth; m_memory = new TData[(int)Math.Pow(2, addrWidth)]; m_initial = initial; if (initial != null && initial.Length > m_memory.Length) { throw new ArgumentException($"You are attempting to set an initial memory with {initial.Length}, but the with {addrWidth} bits you can only store {m_memory.Length} elements"); } if (initial != null) { Array.Copy(initial, m_memory, initial.Length); } }
/// <summary> /// Run this instance. /// </summary> public override async Task Run() { // Wait for initialization to complete await ClockAsync(); m_rdcontrol.Address = 0; m_wrcontrol.Address = 1; m_wrcontrol.Enabled = false; m_rdcontrol.Enabled = true; await ClockAsync(); for (var i = 1; i < m_initial.Length; i++) { m_rdcontrol.Address = i; await ClockAsync(); if (m_rddata.Data.ToString() != VHDLHelper.CreateIntType <TData>((ulong)(i - 1)).ToString()) { Console.WriteLine($"Read problem at offset {i}, value is {m_rddata.Data} but should be {i}"); } } m_rdcontrol.Enabled = false; await ClockAsync(); m_wrcontrol.Enabled = true; for (var i = 1; i < m_rnd.Length; i++) { m_wrcontrol.Address = i; m_wrcontrol.Data = m_rnd[i]; await ClockAsync(); } m_wrcontrol.Enabled = false; await ClockAsync(); m_rdcontrol.Address = 0; m_rdcontrol.Enabled = true; for (var i = 1; i < m_rnd.Length; i++) { m_rdcontrol.Address = i; await ClockAsync(); if (m_rddata.Data.ToString() != m_rnd[i - 1].ToString()) { Console.WriteLine($"Read problem at offset {i}, value is {m_rddata.Data} but should be {i}"); } } }
private string SignalRegion(RenderStateProcess renderer, int indentation) { var memsize = m_memory.Length * DataWidthA; var config = new BlockRamConfig(renderer, DataWidthA, memsize, true); var self = renderer.Process; var outbusa = self.OutputBusses.First(x => typeof(IOutputA).IsAssignableFrom(x.SourceInstance.BusType)); var outbusb = self.OutputBusses.First(x => typeof(IOutputB).IsAssignableFrom(x.SourceInstance.BusType)); var inbusa = self.InputBusses.First(x => typeof(IInputA).IsAssignableFrom(x.SourceInstance.BusType)); var inbusb = self.InputBusses.First(x => typeof(IInputB).IsAssignableFrom(x.SourceInstance.BusType)); string template; if (typeof(TAddress) == typeof(int)) { template = $@" signal ENA_internal: std_logic; signal WEA_internal: std_logic_vector({config.wewidth - 1} downto 0); signal DIA_internal : std_logic_vector({DataWidthA - 1} downto 0); signal DOA_internal : std_logic_vector({DataWidthA - 1} downto 0); signal ADDRA_internal_partial : std_logic_vector({config.realaddrwidth - 1} downto 0); signal ADDRA_internal : std_logic_vector(31 downto 0); signal ENB_internal: std_logic; signal WEB_internal: std_logic_vector({config.wewidth - 1} downto 0); signal DIB_internal : std_logic_vector({DataWidthB - 1} downto 0); signal DOB_internal : std_logic_vector({DataWidthB - 1} downto 0); signal ADDRB_internal_partial : std_logic_vector({config.realaddrwidth - 1} downto 0); signal ADDRB_internal : std_logic_vector(31 downto 0); "; } else { template = $@" signal ENA_internal: std_logic; signal WEA_internal: std_logic_vector({config.wewidth - 1} downto 0); signal DIA_internal : std_logic_vector({DataWidthA - 1} downto 0); signal DOA_internal : std_logic_vector({DataWidthA - 1} downto 0); signal ADDRA_internal : std_logic_vector({config.realaddrwidth - 1} downto 0); signal ENB_internal: std_logic; signal WEB_internal: std_logic_vector({config.wewidth - 1} downto 0); signal DIB_internal : std_logic_vector({DataWidthB - 1} downto 0); signal DOB_internal : std_logic_vector({DataWidthB - 1} downto 0); signal ADDRB_internal : std_logic_vector({config.realaddrwidth - 1} downto 0); "; } return(VHDLHelper.ReIndentTemplate(template, indentation)); }
/// <summary> /// Creates VHDL code that chooses the block ram component data results with the top bits /// </summary> /// <returns>The output selector.</returns> /// <param name="instancename">The name of the instance to create.</param> /// <param name="blocks">The number of blocks.</param> /// <param name="fullAddressWidth">The full address width.</param> /// <param name="blockAddrWidth">The block address width.</param> private string GenerateOutputSelector(string instancename, int blocks, int fullAddressWidth, int blockAddrWidth) { var cases = Enumerable .Range(0, blocks) .Select(i => $@" when ""{VHDLHelper.GetDataBitString(i, fullAddressWidth - blockAddrWidth).Substring(32 - (fullAddressWidth - blockAddrWidth))}"" => DO_internal <= DO_internal_{i};"); return($@" {instancename}_Output: process(ADDR_READ_internal, {string.Join(", ", Enumerable.Range(0, blocks).Select(x => $"DO_internal_{x}"))}) begin case ADDR_READ_internal({fullAddressWidth - 1} downto {blockAddrWidth}) is {string.Join(Environment.NewLine, cases)} when others => -- Implicit latching end case; end process; "); }
/// <summary> /// Creates the signal region /// </summary> /// <returns>The signal region.</returns> /// <param name="renderer">The renderer instance.</param> /// <param name="indentation">The current indentation.</param> private string SignalRegion(RenderStateProcess renderer, int indentation) { var self = renderer.Process; var outbus = self.OutputBusses.First(); var inreadbus = self.InputBusses.First(x => typeof(IReadIn).IsAssignableFrom(x.SourceInstance.BusType)); var inwritebus = self.InputBusses.First(x => typeof(IWriteIn).IsAssignableFrom(x.SourceInstance.BusType)); var memsize = m_memory.Length * DataWidth; var config = new BlockRamConfig(renderer, DataWidth, memsize, false); var rdaddr_partial = string.Empty; var wraddr_partial = string.Empty; string template; if (typeof(TAddress) == typeof(int)) { template = $@" signal RDEN_internal: std_logic; signal WREN_internal: std_logic; signal DI_internal : std_logic_vector({DataWidth - 1} downto 0); signal DO_internal : std_logic_vector({DataWidth - 1} downto 0); signal RDADDR_internal_partial : std_logic_vector({config.realaddrwidth - 1} downto 0); signal WRADDR_internal_partial : std_logic_vector({config.realaddrwidth - 1} downto 0); signal RDADDR_internal : std_logic_vector(31 downto 0); signal WRADDR_internal : std_logic_vector(31 downto 0); "; } else { template = $@" signal RDEN_internal: std_logic; signal WREN_internal: std_logic; signal DI_internal : std_logic_vector({DataWidth - 1} downto 0); signal DO_internal : std_logic_vector({DataWidth - 1} downto 0); signal RDADDR_internal : std_logic_vector({config.realaddrwidth - 1} downto 0); signal WRADDR_internal : std_logic_vector({config.realaddrwidth - 1} downto 0); "; } return(VHDLHelper.ReIndentTemplate(template, indentation)); }
/// <summary> /// Creates the include region for the component /// </summary> /// <returns>The region.</returns> /// <param name="renderer">Renderer.</param> /// <param name="indentation">Indentation.</param> public string IncludeRegion(RenderStateProcess renderer, int indentation) { return(VHDLHelper.CreateComponentInclude(renderer.Parent.Config, indentation)); }
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)); }
private string ProcessRegion(RenderStateProcess renderer, int indentation) { var memsize = m_memory.Length * DataWidthA; var config = new BlockRamConfig(renderer, DataWidthA, memsize, true); var initlines = VHDLHelper.SplitDataBitStringToMemInit( VHDLHelper.GetDataBitStrings(m_initial), config.datawidth, config.paritybits ); var memlines = string.Join( "," + Environment.NewLine, Enumerable.Range(0, int.MaxValue) .Zip( initlines.Item1, (a, b) => string.Format(" INIT_{0:X2} => X\"{1}\"", a, b) ) ); var paritylines = string.Join( "," + Environment.NewLine, Enumerable.Range(0, int.MaxValue) .Zip( initlines.Item2, (a, b) => string.Format(" INITP_{0:X2} => X\"{1}\"", a, b) ) ); var initialvalue = VHDLHelper.GetDataBitString(m_resetinitial, DataWidthA); var self = renderer.Process; var outbusa = self.OutputBusses.First(x => typeof(IOutputA).IsAssignableFrom(x.SourceInstance.BusType)); var outbusb = self.OutputBusses.First(x => typeof(IOutputB).IsAssignableFrom(x.SourceInstance.BusType)); var inbusa = self.InputBusses.First(x => typeof(IInputA).IsAssignableFrom(x.SourceInstance.BusType)); var inbusb = self.InputBusses.First(x => typeof(IInputB).IsAssignableFrom(x.SourceInstance.BusType)); var addrpadding = AddressWidthA < config.realaddrwidth ? string.Empty : string.Format("\"{0}\" & ", new string('0', (config.realaddrwidth - AddressWidthA))); var partialaddrsuffix = typeof(TAddress) == typeof(int) ? "_partial" : string.Empty; var template = $@" {self.InstanceName}_inst : 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 => { DataWidthA }, -- Valid values are 1 - 36(19 - 36 only valid when BRAM_SIZE = ""36Kb"") READ_WIDTH_B => { DataWidthA }, -- 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 => { DataWidthA }, -- Valid values are 1 - 36(19 - 36 only valid when BRAM_SIZE = ""36Kb"") WRITE_WIDTH_B => { DataWidthA }, -- 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, -- Output port-A, width defined by READ_WIDTH_A parameter DOB => DOB_internal, -- Output port-B, width defined by READ_WIDTH_B parameter ADDRA => ADDRA_internal{partialaddrsuffix}, -- Input port-A address, width defined by Port A depth ADDRB => ADDRB_internal{partialaddrsuffix}, -- 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, -- Input port-A data, width defined by WRITE_WIDTH_A parameter DIB => DIB_internal, -- Input port-B data, width defined by WRITE_WIDTH_B parameter ENA => ENA_internal, -- 1-bit input port-A enable ENB => ENB_internal, -- 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, -- Input port-A write enable, width defined by port A depth WEB => WEB_internal -- Input port-B write enable, width defined by port B depth ); -- End of BRAM_TDP_MACRO_inst instantiation {self.InstanceName}_Helper: process(RST,CLK, RDY) begin if RST = '1' then FIN <= '0'; elsif rising_edge(CLK) then FIN <= not RDY; end if; end process; ENA_internal <= ENB and {Naming.ToValidName(renderer.Parent.GetLocalBusName(inbusa, self) + "_" + nameof(IInputA.Enabled)) }; WEA_internal <= (others => ENA_internal and {Naming.ToValidName(renderer.Parent.GetLocalBusName(inbusa, self) + "_" + nameof(IInputA.IsWriting)) }); ADDRA_internal <= { addrpadding }std_logic_vector({ Naming.ToValidName(renderer.Parent.GetLocalBusName(inbusa, self) + "_" + nameof(IInputA.Address)) }); DIA_internal <= std_logic_vector({ Naming.ToValidName(renderer.Parent.GetLocalBusName(inbusa, self) + "_" + nameof(IInputA.Data)) }); { Naming.ToValidName(renderer.Parent.GetLocalBusName(outbusa, self) + "_" + nameof(IOutputA.Data)) } <= {renderer.Parent.VHDLWrappedTypeName(outbusa.Signals.First())}(DOA_internal); ENB_internal <= ENB and {Naming.ToValidName(renderer.Parent.GetLocalBusName(inbusb, self) + "_" + nameof(IInputB.Enabled)) }; WEB_internal <= (others => ENB_internal and {Naming.ToValidName(renderer.Parent.GetLocalBusName(inbusb, self) + "_" + nameof(IInputB.IsWriting)) }); ADDRB_internal <= { addrpadding }std_logic_vector({ Naming.ToValidName(renderer.Parent.GetLocalBusName(inbusb, self) + "_" + nameof(IInputB.Address)) }); DIB_internal <= std_logic_vector({ Naming.ToValidName(renderer.Parent.GetLocalBusName(inbusb, self) + "_" + nameof(IInputB.Data)) }); { Naming.ToValidName(renderer.Parent.GetLocalBusName(outbusb, self) + "_" + nameof(IOutputB.Data)) } <= {renderer.Parent.VHDLWrappedTypeName(outbusa.Signals.First())}(DOB_internal); "; if (partialaddrsuffix != string.Empty) { template += $@" ADDRA_internal_partial <= ADDRA_internal({config.realaddrwidth} downto 0); ADDRB_internal_partial <= ADDRB_internal({config.realaddrwidth} downto 0); "; } return(VHDLHelper.ReIndentTemplate(template, indentation)); }
/// <summary> /// Creates the process region /// </summary> /// <returns>The process region.</returns> /// <param name="renderer">The renderer instance.</param> /// <param name="indentation">The current indentation.</param> private string ProcessRegion(RenderStateProcess renderer, int indentation) { var memsize = m_memory.Length * DataWidth; var config = new BlockRamConfig(renderer, DataWidth, memsize, false); var initlines = VHDLHelper.SplitDataBitStringToMemInit( VHDLHelper.GetDataBitStrings(m_initial), config.datawidth, config.paritybits ); var memlines = string.Join( "," + Environment.NewLine, Enumerable.Range(0, int.MaxValue) .Zip( initlines.Item1, (a, b) => string.Format(" INIT_{0:X2} => X\"{1}\"", a, b) ) ); var paritylines = string.Join( "," + Environment.NewLine, Enumerable.Range(0, int.MaxValue) .Zip( initlines.Item2, (a, b) => string.Format(" INITP_{0:X2} => X\"{1}\"", a, b) ) ); var initialvalue = VHDLHelper.GetDataBitString(m_resetinitial, DataWidth); var self = renderer.Process; var outbus = self.OutputBusses.First(); var inreadbus = self.InputBusses.First(x => typeof(IReadIn).IsAssignableFrom(x.SourceInstance.BusType)); var inwritebus = self.InputBusses.First(x => typeof(IWriteIn).IsAssignableFrom(x.SourceInstance.BusType)); // Apparently, it does not work to do "(others => '1')" var westring = new string('1', config.wewidth); var addrpadding = AddressWidth <= config.realaddrwidth ? string.Empty : string.Format("\"{0}\" & ", new string('0', (config.realaddrwidth - AddressWidth))); var partialaddrsuffix = typeof(TAddress) == typeof(int) ? "_partial" : string.Empty; var template = $@" {self.InstanceName}_inst : BRAM_SDP_MACRO generic map ( BRAM_SIZE => ""{(config.use36k ? "36Kb" : "18Kb")}"", -- Target BRAM, ""18Kb"" or ""36Kb"" DEVICE => ""{ config.targetdevice }"", --Target device: ""VIRTEX5"", ""VIRTEX6"", ""7SERIES"", ""SPARTAN6"" WRITE_WIDTH => { DataWidth }, --Valid values are 1 - 72(37 - 72 only valid when BRAM_SIZE = ""36Kb"") READ_WIDTH => { DataWidth }, --Valid values are 1 - 72(37 - 72 only valid when BRAM_SIZE = ""36Kb"") DO_REG => 0, --Optional output register(0 or 1) INIT_FILE => ""NONE"", SIM_COLLISION_CHECK => ""GENERATE_X_ONLY"", --Collision check enable ""ALL"", ""WARNING_ONLY"", --""GENERATE_X_ONLY"" or ""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, -- Output read data port, width defined by READ_WIDTH parameter DI => DI_internal, -- Input write data port, width defined by WRITE_WIDTH parameter RDADDR => RDADDR_internal{partialaddrsuffix}, -- Input read address, width defined by read port depth RDCLK => CLK, -- 1-bit input read clock RDEN => RDEN_internal, -- 1-bit input read port enable REGCE => '0', -- 1-bit input read output register enable RST => RST, -- 1-bit input reset WE => ""{ westring }"", -- Input write enable, width defined by write port depth WRADDR => WRADDR_internal{partialaddrsuffix}, -- Input write address, width defined by write port depth WRCLK => CLK, -- 1-bit input write clock WREN => WREN_internal -- 1-bit input write port enable ); -- End of BRAM_SDP_MACRO_inst instantiation {self.InstanceName}_Helper: process(RST,CLK, RDY) begin if RST = '1' then FIN <= '0'; elsif rising_edge(CLK) then FIN <= not RDY; end if; end process; RDEN_internal <= ENB and {Naming.ToValidName(renderer.Parent.GetLocalBusName(inreadbus, self) + "_" + nameof(IReadIn.Enabled)) }; RDADDR_internal <= { addrpadding }std_logic_vector({ Naming.ToValidName(renderer.Parent.GetLocalBusName(inreadbus, self) + "_" + nameof(IReadIn.Address)) }); { Naming.ToValidName(renderer.Parent.GetLocalBusName(outbus, self) + "+" + nameof(IReadOut.Data)) } <= {renderer.Parent.VHDLWrappedTypeName(outbus.Signals.First())}(DO_internal); WREN_internal <= ENB and {Naming.ToValidName(renderer.Parent.GetLocalBusName(inwritebus, self) + "_" + nameof(IWriteIn.Enabled)) }; WRADDR_internal <= { addrpadding }std_logic_vector({ Naming.ToValidName(renderer.Parent.GetLocalBusName(inwritebus, self) + "_" + nameof(IWriteIn.Address)) }); DI_internal <= std_logic_vector({ Naming.ToValidName(renderer.Parent.GetLocalBusName(inwritebus, self) + "_" + nameof(IWriteIn.Data)) }); "; if (partialaddrsuffix != string.Empty) { template += $@" RDADDR_internal_partial <= RDADDR_internal({config.realaddrwidth} downto 0); WRADDR_internal_partial <= WRADDR_internal({config.realaddrwidth} downto 0); "; } return(VHDLHelper.ReIndentTemplate(template, indentation)); }
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 addrwidth = (int)Math.Ceiling(Math.Log(initialdata.Length, 2)); var datavhdltype = renderer.Parent.TypeLookup[renderer.Process.InputBusses.First().Signals.First(x => x.Name == nameof(SME.Components.SinglePortMemory <int> .IControl.Data))]; var addrvhdltype = renderer.Parent.TypeLookup[renderer.Process.InputBusses.First().Signals.First(x => x.Name == nameof(SME.Components.SinglePortMemory <int> .IControl.Address))]; var control_bus_data_name = $"{ nameof(SME.Components.SinglePortMemory<int>.Control) }_{ nameof(SME.Components.SinglePortMemory<int>.IControl.Data) }"; var control_bus_addr_name = $"{ nameof(SME.Components.SinglePortMemory<int>.Control) }_{ nameof(SME.Components.SinglePortMemory<int>.IControl.Address) }"; var control_bus_enabled_name = $"{ nameof(SME.Components.SinglePortMemory<int>.Control) }_{ nameof(SME.Components.SinglePortMemory<int>.IControl.Enabled) }"; var control_bus_iswriting_name = $"{ nameof(SME.Components.SinglePortMemory<int>.Control) }_{ nameof(SME.Components.SinglePortMemory<int>.IControl.IsWriting) }"; var readresult_bus_data_name = $"{nameof(SME.Components.SinglePortMemory<int>.ReadResult)}_{ nameof(SME.Components.SinglePortMemory<int>.IReadResult.Data) }"; var asm_write = new AST.AssignmentExpression( new AST.IdentifierExpression( new AST.Signal( control_bus_data_name + "_Vector" ) ), new AST.IdentifierExpression( new AST.Signal( control_bus_data_name ) ) ); var asm_read = new AST.AssignmentExpression( new AST.IdentifierExpression( new AST.Signal( readresult_bus_data_name ) ), new AST.IdentifierExpression( new AST.Signal( readresult_bus_data_name + "_Vector" ) ) ); // Assign the vhdl types so the type conversion is done correctly renderer.Parent.TypeLookup[asm_write.Left] = renderer.Parent.TypeLookup[((AST.IdentifierExpression)asm_write.Left).Target] = renderer.Parent.TypeLookup[asm_read.Right] = renderer.Parent.TypeLookup[((AST.IdentifierExpression)asm_read.Right).Target] = renderer.Parent.TypeScope.GetStdLogicVector(datawidth); renderer.Parent.TypeLookup[asm_write.Right] = renderer.Parent.TypeLookup[((AST.IdentifierExpression)asm_write.Right).Target] = renderer.Parent.TypeLookup[asm_read.Left] = renderer.Parent.TypeLookup[((AST.IdentifierExpression)asm_read.Left).Target] = datavhdltype; var transformer = new Transformations.InjectTypeConversions(renderer.Parent, null); var asm_write_stm = new AST.ExpressionStatement(asm_write); asm_write_stm.UpdateParents(); var asm_read_stm = new AST.ExpressionStatement(asm_read); asm_read_stm.UpdateParents(); transformer.Transform(asm_write); transformer.Transform(asm_read); var template = $@" type ram_type is array ({size - 1} downto 0) of std_logic_vector ({datawidth - 1} downto 0); signal RAM : ram_type := { VHDLHelper.GetArrayAsAssignmentList(initialdata, inverse: true) }; signal { control_bus_data_name }_Vector: std_logic_vector ({datawidth - 1} downto 0); signal { readresult_bus_data_name }_Vector: std_logic_vector ({datawidth - 1} downto 0); signal { control_bus_addr_name }_Vector: std_logic_vector ({addrwidth - 1} downto 0); begin process (CLK) begin if (CLK'event and CLK = '1') then if ({ control_bus_enabled_name } = '1') then { readresult_bus_data_name }_Vector <= RAM(to_integer(unsigned({ control_bus_addr_name }_Vector))); if ({ control_bus_iswriting_name } = '1') then RAM(to_integer(unsigned({ control_bus_addr_name }_Vector))) <= { control_bus_data_name }_Vector; end if; end if; end if; end process; {renderer.Process.InstanceName}_Helper: process(RST, CLK, RDY) begin if RST = '1' then FIN <= '0'; elsif rising_edge(CLK) then FIN <= not RDY; end if; end process; { control_bus_addr_name }_Vector <= STD_LOGIC_VECTOR(resize(unsigned({ control_bus_addr_name }), {addrwidth})); {renderer.Helper.RenderExpression(asm_write_stm.Expression)}; {renderer.Helper.RenderExpression(asm_read_stm.Expression)}; "; return(VHDLHelper.ReIndentTemplate(template, indentation)); }