static void Main(string[] args)
        {
            // Wrapping the whole program into Task.Run() is a workaround for async just to be able to run all this from
            // inside a console app.
            Task.Run(async() =>
            {
                /*
                 * On a high level these are the steps to use Hastlayer:
                 * 1. Create the Hastlayer shell.
                 * 2. Configure hardware generation and generate FPGA hardware representation of the given .NET code.
                 * 3. Generate proxies for hardware-transformed types and use these proxies to utilize hardware
                 *    implementations. (You can see this inside the SampleRunners.)
                 */

                // Configuring the Hastlayer shell. Which flavor should we use? If you're unsure then you'll need
                // the Client flavor: This will let you connect to a remote Hastlayer service to run the software
                // to hardware transformation.
                var hastlayerConfiguration = new HastlayerConfiguration {
                    Flavor = HastlayerFlavor.Developer
                };

                // Initializing a Hastlayer shell. Since this is non-trivial to do you can cache this shell object
                // while the program runs and re-use it continuously. No need to always wrap it into a using() like
                // here, just make sure to Dispose() it before the program terminates.
                using (var hastlayer = await Hastlayer.Create(hastlayerConfiguration))
                {
                    // Hooking into an event of Hastlayer so some execution information can be made visible on the
                    // console.
                    hastlayer.ExecutedOnHardware += (sender, e) =>
                    {
                        Console.WriteLine(
                            "Executing " +
                            e.MemberFullName +
                            " on hardware took " +
                            e.HardwareExecutionInformation.HardwareExecutionTimeMilliseconds +
                            " milliseconds (net) " +
                            e.HardwareExecutionInformation.FullExecutionTimeMilliseconds +
                            " milliseconds (all together)");
                    };


                    // We need to set what kind of device (FPGA/FPGA board) to generate the hardware for.
                    var devices = await hastlayer.GetSupportedDevices();
                    // Let's just use the first one that is available. However you might want to use a specific
                    // device, not just any first one.
                    var configuration = new HardwareGenerationConfiguration(devices.First().Name);

                    // If you're running Hastlayer in the Client flavor, you also need to configure some credentials
                    // here:
                    var remoteClientConfiguration       = configuration.RemoteClientConfiguration();
                    remoteClientConfiguration.AppName   = "TestApp";
                    remoteClientConfiguration.AppSecret = "appsecret";
                    if (hastlayerConfiguration.Flavor == HastlayerFlavor.Client &&
                        remoteClientConfiguration.AppSecret == "appsecret")
                    {
                        throw new InvalidOperationException(
                            "You haven't changed the default remote credentials! Write to [email protected] to receive access if you don't have yet.");
                    }


                    // Letting the configuration of samples run. Check out those methods too!
                    switch (Configuration.SampleToRun)
                    {
                    case Sample.Fix64Calculator:
                        Fix64CalculatorSampleRunner.Configure(configuration);
                        break;

                    case Sample.GenomeMatcher:
                        GenomeMatcherSampleRunner.Configure(configuration);
                        break;

                    case Sample.ParallelAlgorithm:
                        ParallelAlgorithmSampleRunner.Configure(configuration);
                        break;

                    case Sample.ImageProcessingAlgorithms:
                        ImageProcessingAlgorithmsSampleRunner.Configure(configuration);
                        break;

                    case Sample.Loopback:
                        LoopbackSampleRunner.Configure(configuration);
                        break;

                    case Sample.MonteCarloAlgorithm:
                        MonteCarloAlgorithmSampleRunner.Configure(configuration);
                        break;

                    case Sample.ObjectOrientedShowcase:
                        ObjectOrientedShowcaseSampleRunner.Configure(configuration);
                        break;

                    case Sample.PrimeCalculator:
                        PrimeCalculatorSampleRunner.Configure(configuration);
                        break;

                    case Sample.RecursiveAlgorithms:
                        RecursiveAlgorithmsSampleRunner.Configure(configuration);
                        break;

                    case Sample.SimdCalculator:
                        SimdCalculatorSampleRunner.Configure(configuration);
                        break;

                    default:
                        break;
                    }

                    // The generated VHDL code will contain debug-level information, though it will be slower to
                    // create.
                    configuration.VhdlTransformerConfiguration().VhdlGenerationConfiguration = VhdlGenerationConfiguration.Debug;

                    Console.WriteLine("Hardware generation starts.");

                    // Generating hardware from the sample assembly with the given configuration.
                    var hardwareRepresentation = await hastlayer.GenerateHardware(
                        new[]
                    {
                        // Selecting any type from the sample assembly here just to get its Assembly object.
                        typeof(PrimeCalculator).Assembly,
                        typeof(Fix64).Assembly
                    },
                        configuration);

                    Console.WriteLine("Hardware generation finished, writing VHDL source to file.");

                    if (!string.IsNullOrEmpty(Configuration.VhdlOutputFilePath))
                    {
                        await hardwareRepresentation.HardwareDescription.WriteSource(Configuration.VhdlOutputFilePath);
                    }

                    Console.WriteLine("VHDL source written to file, starting hardware execution.");

                    // Running samples.
                    switch (Configuration.SampleToRun)
                    {
                    case Sample.Fix64Calculator:
                        await Fix64CalculatorSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    case Sample.GenomeMatcher:
                        await GenomeMatcherSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    case Sample.ParallelAlgorithm:
                        await ParallelAlgorithmSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    case Sample.ImageProcessingAlgorithms:
                        await ImageProcessingAlgorithmsSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    case Sample.Loopback:
                        await LoopbackSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    case Sample.MonteCarloAlgorithm:
                        await MonteCarloAlgorithmSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    case Sample.ObjectOrientedShowcase:
                        await ObjectOrientedShowcaseSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    case Sample.PrimeCalculator:
                        await PrimeCalculatorSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    case Sample.RecursiveAlgorithms:
                        await RecursiveAlgorithmsSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    case Sample.SimdCalculator:
                        await SimdCalculatorSampleRunner.Run(hastlayer, hardwareRepresentation);
                        break;

                    default:
                        break;
                    }
                }
            }).Wait();

            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
Example #2
0
        static async Task MainTask(string[] args)
        {
            /*
             * On a high level these are the steps to use Hastlayer:
             * 1. Create the Hastlayer shell.
             * 2. Configure hardware generation and generate FPGA hardware representation of the given .NET code.
             * 3. Generate proxies for hardware-transformed types and use these proxies to utilize hardware
             *    implementations. (You can see this inside the SampleRunners.)
             */

            // Configuring the Hastlayer shell. Which flavor should we use? If you're unsure then you'll need
            // the Client flavor: This will let you connect to a remote Hastlayer service to run the software
            // to hardware transformation.
            var hastlayerConfiguration = new HastlayerConfiguration {
                Flavor = HastlayerFlavor.Developer
            };

            // Initializing a Hastlayer shell. Since this is non-trivial to do you can cache this shell object
            // while the program runs and re-use it continuously. No need to always wrap it into a using() like
            // here, just make sure to Dispose() it before the program terminates.
            using (var hastlayer = await Hastlayer.Create(hastlayerConfiguration))
            {
                // Hooking into an event of Hastlayer so some execution information can be made visible on the
                // console.
                hastlayer.ExecutedOnHardware += (sender, e) =>
                {
                    Console.WriteLine(
                        "Executing " +
                        e.MemberFullName +
                        " on hardware took " +
                        e.HardwareExecutionInformation.HardwareExecutionTimeMilliseconds +
                        " milliseconds (net) " +
                        e.HardwareExecutionInformation.FullExecutionTimeMilliseconds +
                        " milliseconds (all together)");
                };


                // A little helper for later.
                var argsList = (IList <string>)args;
                string GetArgument(string name)
                {
                    name = "-" + name;
                    return(args.Contains(name) ? args[argsList.IndexOf(name) + 1] : null);
                }

                // We need to set what kind of device (FPGA/FPGA board) to generate the hardware for.
                var devices = await hastlayer.GetSupportedDevices();

                if (devices == null || !devices.Any())
                {
                    throw new Exception("No devices are available!");
                }

                // Let's just use the first one that is available unless it's specified.
                if (string.IsNullOrEmpty(Configuration.DeviceName))
                {
                    Configuration.DeviceName = devices.First().Name;
                }
                var targetDeviceName = GetArgument("device") ?? Configuration.DeviceName;
                var selectedDevice   = devices.FirstOrDefault(device => device.Name == targetDeviceName);
                if (selectedDevice == null)
                {
                    throw new Exception($"Target device '{targetDeviceName}' not found!");
                }

                var configuration = new HardwareGenerationConfiguration(selectedDevice.Name);

                // If you're running Hastlayer in the Client flavor, you also need to configure some credentials:
                var remoteClientConfiguration = configuration.RemoteClientConfiguration();
                remoteClientConfiguration.AppName   = GetArgument("appname") ?? Configuration.AppName;
                remoteClientConfiguration.AppSecret = GetArgument("appsecret") ?? Configuration.AppSecret;
                if (hastlayerConfiguration.Flavor == HastlayerFlavor.Client &&
                    remoteClientConfiguration.AppSecret == "appsecret")
                {
                    throw new InvalidOperationException(
                              "You haven't changed the default remote credentials! Write to [email protected] to receive access if you don't have yet.");
                }

                // If the sample was selected in the command line use that, or otherwise the default.
                Configuration.SampleToRun = (Sample)Enum.Parse(typeof(Sample), GetArgument("sample") ?? Configuration.SampleToRun.ToString(), true);

                // Letting the configuration of samples run. Check out those methods too!
                switch (Configuration.SampleToRun)
                {
                case Sample.Fix64Calculator:
                    Fix64CalculatorSampleRunner.Configure(configuration);
                    break;

                case Sample.FSharpParallelAlgorithm:
                    FSharpParallelAlgorithmSampleRunner.Configure(configuration);
                    break;

                case Sample.GenomeMatcher:
                    GenomeMatcherSampleRunner.Configure(configuration);
                    break;

                case Sample.ParallelAlgorithm:
                    ParallelAlgorithmSampleRunner.Configure(configuration);
                    break;

                case Sample.ImageProcessingAlgorithms:
                    ImageProcessingAlgorithmsSampleRunner.Configure(configuration);
                    break;

                case Sample.Loopback:
                    LoopbackSampleRunner.Configure(configuration);
                    break;

                case Sample.MemoryTest:
                    MemoryTestSampleRunner.Configure(configuration);
                    break;

                case Sample.MonteCarloPiEstimator:
                    MonteCarloPiEstimatorSampleRunner.Configure(configuration);
                    break;

                case Sample.ObjectOrientedShowcase:
                    ObjectOrientedShowcaseSampleRunner.Configure(configuration);
                    break;

                case Sample.PrimeCalculator:
                    PrimeCalculatorSampleRunner.Configure(configuration);
                    break;

                case Sample.RecursiveAlgorithms:
                    RecursiveAlgorithmsSampleRunner.Configure(configuration);
                    break;

                case Sample.SimdCalculator:
                    SimdCalculatorSampleRunner.Configure(configuration);
                    break;

                default:
                    break;
                }

                // The generated VHDL code will contain debug-level information, though it will be slower to create.
                configuration.VhdlTransformerConfiguration().VhdlGenerationConfiguration = VhdlGenerationConfiguration.Debug;

                Console.WriteLine("Hardware generation starts.");

                // Generating hardware from the sample assembly with the given configuration.
                var hardwareRepresentation = await hastlayer.GenerateHardware(
                    new[]
                {
                    // Selecting any type from the sample assembly here just to get its Assembly object.
                    typeof(PrimeCalculator).Assembly,
                    typeof(Fix64).Assembly,
                    typeof(FSharpSampleAssembly.FSharpParallelAlgorithmContainer).Assembly
                },
                    configuration);

                Console.WriteLine("Hardware generation finished.");
                Console.WriteLine();

                // Be sure to check out transformation warnings. Most of the time the issues noticed shouldn't cause
                // any problems, but sometimes they can.
                if (hardwareRepresentation.HardwareDescription.Warnings.Any())
                {
                    Console.WriteLine(
                        "There were the following transformation warnings, which may hint on issues that can cause the hardware implementation to produce incorrect results:" +
                        Environment.NewLine +
                        string.Join(Environment.NewLine, hardwareRepresentation.HardwareDescription.Warnings.Select(warning => "* " + warning.ToString())));
                    Console.WriteLine();
                }

                if (!string.IsNullOrEmpty(Configuration.VhdlOutputFilePath))
                {
                    Console.WriteLine("Writing VHDL source to file.");

                    await hardwareRepresentation.HardwareDescription.WriteSource(Configuration.VhdlOutputFilePath);

                    Console.WriteLine("VHDL source written to file.");
                    Console.WriteLine();
                }

                Console.WriteLine("Starting hardware execution.");

                // Running samples.
                try
                {
                    switch (Configuration.SampleToRun)
                    {
                    case Sample.Fix64Calculator:
                        await Fix64CalculatorSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.FSharpParallelAlgorithm:
                        await FSharpParallelAlgorithmSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.GenomeMatcher:
                        await GenomeMatcherSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.ParallelAlgorithm:
                        await ParallelAlgorithmSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.ImageProcessingAlgorithms:
                        await ImageProcessingAlgorithmsSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.Loopback:
                        await LoopbackSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.MemoryTest:
                        await MemoryTestSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.MonteCarloPiEstimator:
                        await MonteCarloPiEstimatorSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.ObjectOrientedShowcase:
                        await ObjectOrientedShowcaseSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.PrimeCalculator:
                        await PrimeCalculatorSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.RecursiveAlgorithms:
                        await RecursiveAlgorithmsSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    case Sample.SimdCalculator:
                        await SimdCalculatorSampleRunner.Run(hastlayer, hardwareRepresentation);

                        break;

                    default:
                        break;
                    }
                }
                catch (AggregateException ex) when(ex.InnerException is HardwareExecutionResultMismatchException)
                {
                    // If you set ProxyGenerationConfiguration.VerifyHardwareResults to true (when calling
                    // GenerateProxy()) then everything will be computed in software as well to check the hardware.
                    // You'll get such an exception if there is any mismatch. This shouldn't normally happen, but it's
                    // not impossible in corner cases.
                    var mismatches    = ((HardwareExecutionResultMismatchException)ex.InnerException).Mismatches;
                    var mismatchCount = mismatches.Count();

                    Console.WriteLine($"There {(mismatchCount == 1 ? "was a mismatch" : $"were {mismatchCount} mismatches")} between the software and hardware execution's results! Mismatch{(mismatchCount == 1 ? string.Empty : $"es")}:");