/// <summary> /// Creates a fake process that is used to create the connection /// </summary> /// <param name="state">The validation state to use</param> /// <param name="scope">The active scope</param> /// <param name="connEntry">The connection entry to create the process for</param> /// <returns>A fake process instance</returns> public static Instance.Process CreateConnectProcess(Validation.ValidationState state, Validation.ScopeState scope, AST.ConnectEntry connEntry) { var lhs = state.FindSymbol(connEntry.Source, scope) ?? throw new ParserException($"Could not resolve symbol {connEntry.Source.SourceToken}", connEntry.Source); var rhs = state.FindSymbol(connEntry.Target, scope) ?? throw new ParserException($"Could not resolve symbol {connEntry.Target.SourceToken}", connEntry.Target); if (lhs is Instance.Signal lhs_signal && rhs is Instance.Signal rhs_signal) { return(IdentityHelper.CreateIdentityProcess( state, scope, connEntry.SourceToken, // Extract the bus name locally new Name(connEntry.Source.SourceToken, connEntry.Source.Identifier.SkipLast(1).ToArray(), null).AsExpression(), new Name(connEntry.Target.SourceToken, connEntry.Target.Identifier.SkipLast(1).ToArray(), null).AsExpression(), // Assign just the named entry new[] { lhs_signal.Source }, // Ensure we use the same type to avoid silent type-casting new[] { new BusSignalDeclaration(connEntry.Target.SourceToken, rhs_signal.Source.Name, lhs_signal.Source.Type, null, AST.SignalDirection.Normal ) }, Instance.ProcessType.Connect )); }
/// <summary> /// Creates instances for all signals of a bus /// </summary> /// <param name="state">The state to use</param> /// <param name="parent">The bus to create the signal instances for</param> private void CreateAndRegisterInstance(Validation.ValidationState state, Instance.Bus parent) { var scope = state.CurrentScope; foreach (var signal in parent.Source.Signals) { var s = new Instance.Signal(parent, signal); scope.TryAddSymbol(s.Name, s, signal.Name); parent.Instances.Add(s); } }
/// <summary> /// Performs a lookup to find the symbol and returns the datatype of the found symbol /// </summary> /// <param name="state">The current state</param> /// <param name="scope">The scope to use</param> /// <param name="name">The name to find</param> /// <returns>The datatype or <c>null</c></returns> private static DataType FindDataType(Validation.ValidationState state, AST.NameExpression name, ScopeState scope) { var symb = state.ResolveSymbol(name, scope); if (symb == null) { throw new ParserException($"Unable to find instance for name: {name.Name}", name); } if (symb is Instance.Variable variable) { return(variable.ResolvedType = state.ResolveTypeName(variable.Source.Type, scope)); } else if (symb is Instance.Bus bus) { return(state.ResolveBusSignalTypes(bus, scope)); } else if (symb is Instance.Signal signal) { return(signal.ResolvedType = state.ResolveTypeName(signal.Source.Type, scope)); } else if (symb is Instance.ConstantReference constant) { return(constant.ResolvedType = state.ResolveTypeName(constant.Source.DataType, scope)); } else if (symb is Instance.EnumFieldReference efr) { return(new AST.DataType(name.SourceToken, efr.ParentType.Source)); } else if (symb is Instance.Literal literalInstance) { if (literalInstance.Source is AST.BooleanConstant) { return(new AST.DataType(literalInstance.Source.SourceToken, ILType.Bool, 1)); } else if (literalInstance.Source is AST.IntegerConstant) { return(new AST.DataType(literalInstance.Source.SourceToken, ILType.SignedInteger, -1)); } else if (literalInstance.Source is AST.FloatingConstant) { return(new AST.DataType(literalInstance.Source.SourceToken, ILType.Float, -1)); } } return(null); }
/// <summary> /// Creates all sub-instances from declarations /// </summary> /// <param name="state">The state to use</param> /// <param name="declarations">The declarations to process</param> /// <param name="parentInstances">The collection of instances to append to</param> private void CreateAndRegisterInstancesForDeclarations(Validation.ValidationState state, IEnumerable <AST.Declaration> declarations, List <Instance.IInstance> parentInstances) { var scope = state.CurrentScope; // Add all variables and locally defined busses foreach (var decl in declarations) { if (decl is EnumDeclaration en) { var e = new Instance.EnumTypeReference(en); scope.TryAddSymbol(e.Name, e, en.Name); using (state.StartScope(e)) CreateAndRegisterInstance(state, e); parentInstances.Add(e); } else if (decl is FunctionDefinition fdef) { scope.TryAddSymbol(fdef.Name.Name, decl, fdef.Name); } else if (decl is ConstantDeclaration cdecl) { var c = new Instance.ConstantReference(cdecl); scope.TryAddSymbol(c.Name, c, cdecl.Name); parentInstances.Add(c); } else if (decl is VariableDeclaration variable) { var v = new Instance.Variable(variable); scope.TryAddSymbol(v.Name, v, variable.Name); parentInstances.Add(v); } else if (decl is BusDeclaration bus) { var b = new Instance.Bus(bus); scope.TryAddSymbol(b.Name, b, bus.Name); using (state.StartScope(b)) CreateAndRegisterInstance(state, b); parentInstances.Add(b); } else { throw new ParserException($"Unable to process {decl.GetType()} inside a process", decl); } } }
/// <summary> /// Creates all sub-instances for a process /// </summary> /// <param name="state">The state to use</param> /// <param name="parent">The parent process</param> private void CreateAndRegisterInstance(Validation.ValidationState state, Instance.Process parent) { var scope = state.CurrentScope; CreateAndRegisterInstancesForDeclarations(state, parent.ProcessDefinition.Declarations, parent.Instances); // TODO: The scope should work within the statement tree. We can have nested statements.... foreach (var loop in parent.Statements.All().OfType <AST.ForStatement>()) { var l = new Instance.ForLoop(loop.Current); using (var sc = state.StartScope(l, loop.Current)) { var varinst = new Instance.Variable(loop.Current.Variable); sc.TryAddSymbol(loop.Current.Variable.Name.Name, varinst, loop.Current.Variable.SourceToken); } parent.Instances.Add(l); } // Find all function invocations so we can map parameters foreach (var func in parent.Statements.All().OfType <AST.FunctionStatement>()) { var fdef = state.FindSymbol(func.Current.Name, scope); if (fdef == null) { throw new ParserException($"No function named {func.Current.Name.AsString} found", func.Current); } if (!(fdef is AST.FunctionDefinition ffdef)) { throw new ParserException($"Expected a function for {func.Current.Name.AsString}, but found {fdef.GetType()}", func.Current); } var f = new Instance.FunctionInvocation(ffdef, func.Current); using (var sc = state.StartScope(f)) CreateAndRegisterInstancesForDeclarations(state, ffdef.Declarations, f.Instances); parent.Instances.Add(f); } }
/// <summary> /// Creates and registers all network declaration instances /// </summary> /// <param name="state">The state to use</param> /// <param name="networkDecls">The network declarations to instantiate</param> /// <param name="parentCollection"></param> private void CreateAndRegisterInstances(Validation.ValidationState state, IEnumerable <NetworkDeclaration> networkDecls, IList <Instance.IInstance> parentCollection) { var scope = state.CurrentScope; foreach (var decl in networkDecls) { if (decl is AST.BusDeclaration bus) { var b = new Instance.Bus(bus); scope.TryAddSymbol(b.Name, b, bus.Name); using (state.StartScope(b)) CreateAndRegisterInstance(state, b); parentCollection.Add(b); } else if (decl is AST.ConstantDeclaration cdecl) { var cref = new Instance.ConstantReference(cdecl); scope.TryAddSymbol(cref.Name, cref, cdecl.Name); parentCollection.Add(cref); continue; } else if (decl is AST.GeneratorDeclaration genDecl) { var startSymbol = state.ResolveToInteger(genDecl.SourceExpression, scope); var finishSymbol = state.ResolveToInteger(genDecl.TargetExpression, scope); // TODO: Need to fix array support for this to work correctly? for (var i = startSymbol; i < finishSymbol; i++) { CreateAndRegisterInstances(state, genDecl.Networks, parentCollection); } } else if (decl is AST.InstanceDeclaration instDecl) { var sym = state.FindSymbol(instDecl.SourceItem, scope); if (sym != null && sym is AST.Network netw) { // Recursively create network // TODO: Guard against infinite recursion parentCollection.Add(CreateAndRegisterInstance(state, instDecl, netw)); } else if (sym != null && sym is AST.Process proc) { var p = new Instance.Process(instDecl, proc, Instance.ProcessType.Normal); if (instDecl.Name.Name != null) { scope.TryAddSymbol(instDecl.Name.Name.Name, p, instDecl.Name.Name); } using (state.StartScope(p, instDecl)) CreateAndRegisterInstance(state, p); parentCollection.Add(p); } else { if (sym == null) { throw new ParserException($"No item found with the name {instDecl.SourceItem}", decl); } else { throw new ParserException($"The item {instDecl.SourceItem} is not a process, but a {sym.GetType().Name}", decl); } } } else if (decl is AST.ConnectDeclaration connDecl) { foreach (var connEntry in connDecl.Entries) { var p = IdentityHelper.CreateConnectProcess(state, scope, connEntry); using (state.StartScope(p, connEntry)) CreateAndRegisterInstance(state, p); parentCollection.Add(p); } } else { throw new ParserException($"Attempted to create an instance of type: {decl.GetType()}", decl); } } }
/// <summary> /// Creates the VHDL output files /// </summary> /// <param name="state">The validated network to create the files for</param> /// <param name="outputfolder">The folder to use as the base for the VHDL output</param> /// <param name="options">The options for creating the code</param> public static void CreateFiles(Validation.ValidationState state, string outputfolder, Program.Options options) { if (options.GHDLStandard != "93" && options.GHDLStandard != "93c") { throw new ParserException("Only 93 and 93c are currently supported", null); } var vhdlout = Path.GetFullPath(Path.Combine(outputfolder, options.VHDLOutputFolder)); if (options.ClearTargetFolder && Directory.Exists(vhdlout)) { if (string.IsNullOrWhiteSpace(options.VHDLOutputFolder) || options.VHDLOutputFolder.Trim().StartsWith("/")) { throw new ArgumentException($"Refusing to delete folder, please supply a relative path: {options.VHDLOutputFolder}"); } Directory.Delete(vhdlout, true); } if (!Directory.Exists(vhdlout)) { Directory.CreateDirectory(vhdlout); } var config = new RenderConfig(); if (options.CreateAocFiles) { Console.WriteLine("Note: aoc file generation activated, forcing options to be compatible with aoc output"); config.REMOVE_ENABLE_FLAGS = true; config.RESET_SIGNAL_NAME = "resetn"; config.CLOCK_SIGNAL_NAME = "clock"; config.RESET_ACTIVE_LOW = true; options.VHDLFileExtensions = "vhd"; } var generator = new Codegen.VHDL.VHDLGenerator(state, config) { CSVTracename = options.TraceFile, Ticks = File.Exists(options.TraceFile) ? File.ReadAllLines(options.TraceFile).Count() + 2 : 100, CustomFiles = options.ExtraVHDLFiles }; var rs = new Codegen.VHDL.VHDLGenerator.RenderState(); var export = generator.GenerateExportModule(rs); File.WriteAllText(Path.Combine(vhdlout, Path.ChangeExtension("export.vhdl", options.VHDLFileExtensions)), export); var custtypes = generator.GenerateCustomTypes(rs); File.WriteAllText(Path.Combine(vhdlout, Path.ChangeExtension("customtypes.vhdl", options.VHDLFileExtensions)), custtypes); var tdoc = generator.GenerateMainModule(rs); File.WriteAllText(Path.Combine(vhdlout, Path.ChangeExtension("toplevel.vhdl", options.VHDLFileExtensions)), tdoc); var tbdoc = generator.GenerateTestbench(rs); File.WriteAllText(Path.Combine(vhdlout, Path.ChangeExtension("testbench.vhdl", options.VHDLFileExtensions)), tbdoc); var filenames = new Dictionary <Instance.Process, string>(); foreach (var p in generator.AllRenderedProcesses) { var doc = generator.GenerateProcess(rs, p); var fn = filenames[p] = generator.ProcessNames[p]; File.WriteAllText(Path.Combine(vhdlout, Path.ChangeExtension(fn + ".vhdl", options.VHDLFileExtensions)), doc); } if (options.CreateXpf) { var txpf = generator.GenerateXpf(rs, filenames, options.VHDLFileExtensions); File.WriteAllText(Path.Combine(vhdlout, $"project.xpf"), txpf); } if (options.CreateAocFiles) { var aoclproj = generator.GenerateAocl(rs, filenames, options.VHDLFileExtensions); File.WriteAllText(Path.Combine(vhdlout, $"opencl_lib.xml"), aoclproj); } var makefile = generator.GenerateMakefile(rs, filenames, options.GHDLStandard, options.VHDLFileExtensions); File.WriteAllText(Path.Combine(vhdlout, $"Makefile"), makefile); generator.CopySupportFiles(vhdlout); }