public static String GetEntrypointsString(Microprogram microprogram, Boolean generateDebugInfo = false) { String entrypoints = ""; int addressLength = Convert.ToString(microprogram.MicroprogramLength - 1, 2).Length; //Bit length of entrypoint addresses for (int i = 0; i < Math.Pow(2, microprogram.OpcodeWidth); i++) { if (microprogram.InstructionEntrypoints.ContainsKey(i)) { String symbol = microprogram.InstructionEntrypoints[i]; Sequence sequence; if ((sequence = microprogram[symbol] as Sequence) == null) { throw new MicroassemblerWriteException($"Symbol {symbol} bound to entrypoint {i} does not exist"); } if (sequence.IsMacro) { throw new MicroassemblerWriteException($"Symbol {symbol} bound to entrypoint {i} is a macro (macros cannot be bound to entrypoints)"); } entrypoints += Convert.ToString(sequence.Address, 2).PadLeft(addressLength, '0'); if (generateDebugInfo) { entrypoints += $" //Instruction Entrypoint {i} at sequence {symbol} (address {sequence.Address})"; } entrypoints += "\n"; } else { entrypoints += new String('0', addressLength) + ((generateDebugInfo) ? $" //Instruction entrypoint {i} is unused\n" : "\n"); } } return(entrypoints); }
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 static void WriteMicroprogram(Microprogram microprogram, List <Sequence> placedSequences, String path, Boolean generateDebugInfo = false) { String program = GetMicroprogramString(microprogram, placedSequences, generateDebugInfo); String entrypoints = GetEntrypointsString(microprogram, generateDebugInfo); StreamWriter writer = new StreamWriter(path + "/Microprogram"); writer.Write(program); writer.Dispose(); writer = new StreamWriter(path + "/Entrypoints"); writer.Write(entrypoints); writer.Dispose(); }
public static String GetMicroprogramString(Microprogram microprogram, List <Sequence> placedSequences, Boolean generateDebugInfo = false) { int filled = 0; String program = ""; foreach (Sequence sequence in placedSequences) { if (generateDebugInfo) { program += $"//Sequence '{sequence.Symbol}' at address {sequence.Address}\n"; } BitArray[] steps = ProcessSequence(sequence, microprogram); filled += steps.Length; steps.EachIndex((s, i) => { program += s.ToBitString(); if (generateDebugInfo) { String labels = GetLocalLabels(sequence, i); if (!String.IsNullOrEmpty(labels)) { program += $" //{labels} (address {sequence.Address + i})"; } } program += "\n"; }); if (generateDebugInfo) { program += "\n"; } } //Fill the rest of the program with the defined empty step if (generateDebugInfo) { program += $"//Empty space ({microprogram.MicroprogramLength - filled} unused addresses)\n"; } String emptyStep = ProcessStep(microprogram.EmptyAssertion, microprogram).ToBitString(); for (int i = 0; i < microprogram.MicroprogramLength - filled; i++) { program += emptyStep + "\n"; } return(program); }
public List <Sequence> PlaceMicroprogram(Microprogram microprogram) //Assign each sequence an absolute starting address and return a list of all sequences in order. Assign the fetch sequence to address 0 { int currAddress = 0; List <Sequence> placedSequences = new List <Sequence>(); Sequence fetchSequence = microprogram[microprogram.FetchEntrypoint] as Sequence; if (fetchSequence == null) { throw new MicroassemblerLinkException($"Fetch sequence '{microprogram.FetchEntrypoint}' was not found"); } if (fetchSequence.IsMacro) { throw new MicroassemblerLinkException($"Fetch sequence '{microprogram.FetchEntrypoint}' is defined as a Macro"); } fetchSequence.Address = 0; RecurseAssignBaseAddress(fetchSequence, 0); currAddress += fetchSequence.Steps.Count; placedSequences.Add(fetchSequence); foreach (KeyValuePair <String, Object> kv in microprogram.Symbols) { if (kv.Value is Sequence && kv.Value != fetchSequence) { Sequence sequence = kv.Value as Sequence; if (sequence.IsMacro) { continue; //Do NOT place macros } sequence.Address = currAddress; //Assign sequence base address RecurseAssignBaseAddress(sequence, currAddress); currAddress += sequence.Steps.Count; placedSequences.Add(sequence); } } if (currAddress > microprogram.MicroprogramLength - 1) { throw new MicroassemblerLinkException($"Placed microprogram is of length {currAddress + 1} which exceeds the maximum length of {microprogram.MicroprogramLength}"); } return(placedSequences); }
static void Main(string[] args) { Console.WriteLine(new BitMask(62, 0).ToLongMask()); StreamReader reader = new StreamReader("Microprogram.mal"); String file = reader.ReadToEnd(); reader.Dispose(); MicroprogramParser parser = new MicroprogramParser(); Microprogram microprogram = parser.ParseProgram(file); MicroprogramExpander expander = new MicroprogramExpander(); expander.ExpandMicroprogram(microprogram); MicroprogramLinker linker = new MicroprogramLinker(); List <Sequence> placedSequences = linker.PlaceMicroprogram(microprogram); linker.ResolveSymbols(microprogram, placedSequences); MicroprogramFileWriter.WriteMicroprogram(microprogram, placedSequences, System.IO.Directory.GetCurrentDirectory(), true); Console.WriteLine(); }
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 static BitArray[] ProcessSequence(Sequence sequence, Microprogram microprogram) { BitArray[] arrays = new BitArray[sequence.Steps.Count]; sequence.Steps.EachIndex((s, i) => arrays[i] = ProcessStep(s, microprogram)); return(arrays); }
public Microprogram ParseProgram(String program) { Microprogram = new Microprogram(); Enumerator = Tokenizer.Tokenize(program); if (Enumerator == null) { return(null); } while (Enumerator.HasToken()) { Token token = Enumerator.Current; Enumerator.Advance(); if (token.TokenType == TokenType.Word) { String keyword = (String)token.Value; switch (keyword.ToLower()) { case "config": if (!ProcessConfigs()) { return(null); } break; case "const": if (!ProcessConstant()) { return(null); } break; case "control": if (!ProcessControlWordLabel()) { return(null); } break; case "sequence": if (!ProcessSequence()) { return(null); } break; case "macro": if (!ProcessMacro()) { return(null); } break; case "empty": if (!ParseEmpty()) { return(null); } break; case "entrypoints": if (!ParseEntrypoints()) { return(null); } break; default: throw new MicroassemblerParseException(token, "Keyword expected"); } } else { throw new MicroassemblerParseException(token, "Keyword expected"); } } //Config sanity checks if (Microprogram.MicroprogramLength <= 0) { throw new MicroassemblerParseException($"The microprogram length must be greater than zero"); } if (Microprogram.OpcodeWidth <= 0) { throw new MicroassemblerParseException($"The opcode width must be greater than zero"); } if (Microprogram.ControlWordWidth <= 0) { throw new MicroassemblerParseException($"The control word width must be greater than zero"); } if (Microprogram.BankSelectorMask.Length <= 0) { throw new MicroassemblerParseException($"The bank selector width must be greater than zero"); } if (Microprogram.BankSelectorMask.Length + 1 >= Microprogram.ControlWordWidth) { throw new MicroassemblerParseException($"Control word width of {Microprogram.ControlWordWidth} is invalid, as the bank selector has a width of {Microprogram.BankSelectorMask.Length}"); } //Check control word label lengths foreach (ControlWordLabel cw in Microprogram.ControlWordLabels.Values) { if (cw.Mask.Length <= 0) { throw new MicroassemblerParseException($"Control word label {cw.Name} must have a length that is geater than zero"); } if (cw.Mask.Length + Microprogram.BankSelectorMask.Length > Microprogram.ControlWordWidth) { throw new MicroassemblerParseException($"Control word label {cw.Name} exceeds the maximum control word width of {Microprogram.ControlWordWidth - Microprogram.BankSelectorMask.Length}"); } } return(Microprogram); }