public static BitArray ProcessStep(SequenceStep step, Microprogram microprogram) { if (step.Type == SequenceStepType.MacroReference) { throw new MicroassemblerWriteException($"Unexpanded macro found on line {step.Line}"); } SequenceAssertion assertion = step as SequenceAssertion; BitArray array = new BitArray((int)microprogram.ControlWordWidth); array[microprogram.BankSelectorMask] = (ulong)assertion.Bank; int bankOffset = microprogram.BankSelectorMask.Length; foreach (KeyValuePair <ControlWordLabel, Object> signal in assertion.AssertedSignals) { if (!(signal.Value is long)) { throw new MicroassemblerWriteException($"Invalid/unresolved symbol {signal.Value} in assertion on line {assertion.Line}"); } long value = (long)signal.Value; if (value > (long)signal.Key.Mask.MaxValue) { Console.WriteLine($"Warning: Asserted signal {signal.Key.Name} on line {assertion.Line} has a maximum value of {signal.Key.Mask.MaxValue} (actual assertion of {value} will be truncated)"); } array[signal.Key.Mask, bankOffset] = (ulong)value; } return(array); }
public Boolean ParseEmpty() { SequenceAssertion assertion = ParseSequenceAssertion(); Microprogram.EmptyAssertion = assertion; return(true); }
public SequenceAssertion ParseSequenceAssertion() //Parses an assertion statement { SequenceAssertion assertion = new SequenceAssertion(); VerifySyntaxToken(TokenType.OpenBlock, "{"); int startLine = Enumerator.Last.Line; assertion.Line = startLine; while (true) { if (!Enumerator.HasToken()) { throw new MicroassemblerParseException($"Unfinished assertion statement on line {startLine}"); } Token token = Enumerator.Current; Enumerator.Advance(); if (token.TokenType == TokenType.CloseBlock) { break; } else if (token.TokenType == TokenType.Pair) { Object labelName = (token.Value as Object[])[0]; Object labelValue = (token.Value as Object[])[1]; if (!(labelName is String)) { throw new MicroassemblerParseException($"Invalid assertion key on line {token.Line}"); } if (!Microprogram.ControlWordLabels.ContainsKey(labelName.ToString())) { throw new MicroassemblerParseException($"Nonexistant control word label on line {token.Line}"); } assertion.AddAssertion(Microprogram.ControlWordLabels[labelName.ToString()], labelValue); if (Enumerator.HasNext() && Enumerator.Next.TokenType == TokenType.Pair) { VerifySyntaxToken(TokenType.ListDelimeter, ","); } if (Enumerator.HasNext() && Enumerator.Next.TokenType == TokenType.CloseBlock) { DiscardOptionalToken(TokenType.ListDelimeter, ","); } } else { throw new MicroassemblerParseException(token); } } if (assertion.AssertedSignals.Count > 0) { List <ControlWordLabel> overlaps = assertion.AssertedSignals.Where(signal1 => assertion.AssertedSignals.Any(signal2 => (!signal2.Equals(signal1) && signal1.Key.Mask.OverlapsWith(signal2.Key.Mask)))).Select(kv => kv.Key).ToList(); if (overlaps.Count > 0) { Console.WriteLine($"Warning: Assertion on line {startLine} contains overlapping signals: {String.Join(", ", overlaps.Select(o => o.Name))}"); } } return(assertion); }
public void ExpandMicroprogram(Microprogram microprogram) //Expands all macro references and resolves constants/macro variables { Microprogram = microprogram; Sequence sequence; do { sequence = microprogram.Symbols.Where(kv => ((kv.Value is Sequence) && (kv.Value as Sequence).Unexpanded && !(kv.Value as Sequence).IsMacro && (kv.Value as Sequence).Steps.Count > 0)).Select(kv => (Sequence)kv.Value).FirstOrDefault(); //Get first unexpanded sequence if (sequence == null) { break; } int macroAddr; for (macroAddr = 0; macroAddr < sequence.Steps.Count; macroAddr++) { if (sequence.Steps[macroAddr].Type == SequenceStepType.MacroReference) { break; //Find the first macro reference within the sequence } } SequenceMacroReference mRef = sequence.Steps[macroAddr] as SequenceMacroReference; if (microprogram[mRef.Symbol] == null || !(microprogram[mRef.Symbol] is Sequence)) { throw new MicroassemblerExpansionException($"Macro {mRef.Symbol} referenced on line {mRef.Line} does not exist"); } Sequence macro = (Sequence)Microprogram[mRef.Symbol]; if (macro.Parameters.Count > mRef.Arguments.Count) { throw new MicroassemblerExpansionException($"Macro reference on line {mRef.Line} provides {mRef.Arguments.Count} arguments, while the referenced macro has {macro.Parameters.Count} parameters"); } List <SequenceStep> copiedSteps = macro.Steps.Select(s => (SequenceStep)s.Clone()).ToList(); //Find a unique expansion symbol String expansionSymbol; int symNum = 0; do { expansionSymbol = ((String.IsNullOrEmpty(mRef.ParentReference)) ? "_" : mRef.ParentReference + "._") + mRef.Symbol + "_" + symNum.ToString(); symNum++; }while (sequence[expansionSymbol] != null); //Recursively Offset all address symbols after the macro RecurseOffset(sequence, macroAddr, macro.Steps.Count - 1); //The macro call step is removed, so that is not counted as part of the offset //Create a container for symbols within the expanded macro and copy symbols from the original macro SymbolContainer expansionContainer = new SymbolContainer(); macro.Symbols.ForEach(kv => expansionContainer.Symbols.Add(kv.Key, (kv.Value is ICloneable) ? (kv.Value as ICloneable).Clone() : kv.Value)); sequence[expansionSymbol] = expansionContainer; expansionContainer.Symbols.ForEach(kv => OffsetObject(kv.Value, macroAddr)); //Replace parameter references in copied steps with arguments, also add the expanded symbol name to any internal macro symbol references foreach (SequenceStep step in copiedSteps) { if (step is SequenceMacroReference) { SequenceMacroReference stepRef = step as SequenceMacroReference; if (stepRef.Symbol.Equals(mRef.Symbol)) { throw new MicroassemblerExpansionException($"Caught recursive macro self-reference on line {stepRef.Line}"); //Sanity check } stepRef.Arguments = stepRef.Arguments.Select(a => SubArgumentsAndSymbols(a, macro, mRef, expansionSymbol)).ToList(); stepRef.ParentReference = expansionSymbol; } else if (step is SequenceAssertion) { SequenceAssertion stepAssertion = step as SequenceAssertion; stepAssertion.AssertedSignals = stepAssertion.AssertedSignals.Select(kv => new KeyValuePair <ControlWordLabel, Object>(kv.Key, SubArgumentsAndSymbols(kv.Value, macro, mRef, expansionSymbol))).ToDictionary(kv => kv.Key, kv => kv.Value); } } //Remove macro reference and insert steps sequence.Steps.RemoveAt(macroAddr); sequence.Steps.InsertRange(macroAddr, copiedSteps); }while (sequence != null); }
public void ResolveSymbols(Microprogram microprogram, List <Sequence> placedSequences) //Resolve all symbol references to numeric values { foreach (Sequence sequence in placedSequences) { foreach (SequenceStep step in sequence.Steps) { if (step is SequenceMacroReference) { throw new MicroassemblerLinkException($"Encountered unexpanded macro on line {step.Line}"); } if (step is SequenceAssertion) { SequenceAssertion assertion = step as SequenceAssertion; foreach (ControlWordLabel key in assertion.AssertedSignals.Keys.ToList()) { Object value = assertion.AssertedSignals[key]; if (!(value is long)) { String symbol = value.ToString(); SymbolSelector sel = SymbolSelector.TryParse(symbol); if (sel != null) { if (long.TryParse(sel.Symbol, out long intValue)) { assertion.AssertedSignals[key] = (intValue & sel.Selector.ToLongMask()) >> sel.Selector.LowerBound; } else { symbol = sel.Symbol; Object resolvedSymbol = (sequence[symbol] != null) ? sequence[symbol] : microprogram[symbol]; if (resolvedSymbol == null) { throw new MicroassemblerLinkException($"Symbol {symbol} referenced by assertion on line {assertion.Line} is not defined"); } if (resolvedSymbol is ISymbolResolver) { resolvedSymbol = (resolvedSymbol as ISymbolResolver).Resolve(); } if (!(resolvedSymbol is long)) { throw new MicroassemblerLinkException($"Symbol {symbol} resolved to {resolvedSymbol}, all symbols should resolve to a number"); } assertion.AssertedSignals[key] = ((long)resolvedSymbol & sel.Selector.ToLongMask()) >> sel.Selector.LowerBound; } } else { Object resolvedSymbol = (sequence[symbol] != null) ? sequence[symbol] : microprogram[symbol]; if (resolvedSymbol == null) { throw new MicroassemblerLinkException($"Symbol {symbol} referenced by assertion on line {assertion.Line} is not defined"); } if (resolvedSymbol is ISymbolResolver) { resolvedSymbol = (resolvedSymbol as ISymbolResolver).Resolve(); } if (!(resolvedSymbol is long)) { throw new MicroassemblerLinkException($"Symbol {symbol} resolved to {resolvedSymbol}, all symbols should resolve to a number"); } assertion.AssertedSignals[key] = resolvedSymbol; } } } } } } //Resolve empty step SequenceAssertion emptyAssertion = microprogram.EmptyAssertion; if (microprogram.EmptyAssertion == null) { throw new MicroassemblerLinkException("The empty/default sequence step is not defined"); } foreach (ControlWordLabel key in emptyAssertion.AssertedSignals.Keys.ToList()) { Object value = emptyAssertion.AssertedSignals[key]; if (!(value is long)) { String symbol = value.ToString(); Object resolvedSymbol = microprogram[symbol]; if (resolvedSymbol == null) { throw new MicroassemblerLinkException($"Symbol {symbol} referenced by assertion on line {emptyAssertion.Line} is not defined"); } if (resolvedSymbol is ISymbolResolver) { resolvedSymbol = (resolvedSymbol as ISymbolResolver).Resolve(); } emptyAssertion.AssertedSignals[key] = resolvedSymbol; } } }
public Sequence ParseSequence(Boolean isMacro) // Parses a sequence and return an object representation (used for both normal sequences and macros) { Sequence sequence = new Sequence() { IsMacro = isMacro }; if (Enumerator.HasToken() && Enumerator.Current.TokenType == TokenType.ParenList) { if (!isMacro) { throw new MicroassemblerParseException(Enumerator.Last, "Only macros can define a parameter list"); } List <Object> parameters = (List <Object>)Enumerator.Current.Value; Enumerator.Advance(); if (parameters.Where(p => !(p is String) || (p is String && ((String)p).Any(Char.IsWhiteSpace))).Any()) { throw new MicroassemblerParseException(Enumerator.Last, "Parameter definitions may only contain non-whitespace-delimited words"); } sequence.Parameters.AddRange(parameters.Cast <String>()); } VerifySyntaxToken(TokenType.OpenBlock, "{"); String word = ""; do { if (Enumerator.HasToken() && Enumerator.Current.TokenType == TokenType.CloseBlock) { Enumerator.Advance(); break; } word = GetWordToken(); if (word.StartsWith("::") && word.EndsWith("::")) { String label = word.Substring(2, word.Length - 4); sequence[label] = new SequenceLabel { LocalAddress = sequence.Steps.Count }; } else if (Enumerator.HasToken() && Enumerator.Current.TokenType == TokenType.ParenList) { List <Object> arguments = (List <Object>)Enumerator.Current.Value; Enumerator.Advance(); SequenceMacroReference step = new SequenceMacroReference() { Arguments = arguments, Symbol = word, Line = Enumerator.Last.Line }; sequence.Steps.Add(step); } else if (word.ToLower().Equals("assert")) { SequenceAssertion step = ParseSequenceAssertion(); sequence.Steps.Add(step); } else { throw new MicroassemblerParseException(Enumerator.Last); } }while (true); return(sequence); }