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);
        }
Example #2
0
        /// <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}");
                }
            }
        }
Example #4
0
        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));
        }
Example #5
0
        /// <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;
");
        }
Example #6
0
        /// <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));
        }
Example #7
0
 /// <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));
 }
Example #8
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));
        }
Example #9
0
        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));
        }
Example #10
0
        /// <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));
        }
Example #11
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 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));
        }