/** * Scan and the source (pass 2) and generate text and modification * records as apporpriate. * * @refcode OB * @errtest * N/A * @errmsg * N/A * @author Jacob Peddicord * @creation May 9, 2011 * @modlog * - May 10, 2011 - Jacob - Implemented some modification record things * - May 10, 2011 - Jacob - Refactored line iteration a bit * - May 11, 2011 - Jacob - Fix how we determine the type and number of modifications * - May 13, 2011 - Mark - Implement expression processing * - May 13, 2011 - Mark - Fix one of the expression cases with modifications * - May 14, 2011 - Mark - Implement ADC/e! * - May 14, 2011 - Mark - Adjust error handling code * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private void GenerateSourceRecords() { foreach (IntermediateLine line in this.input) { //Console.WriteLine(this.SourceLine) // skip lines that won't be in the object file if (line.ProgramCounter == null) { // special case: RESET directive should generate a linking record if (line.Directive == "RESET" && line.GetThreeErrors().Count == 0) { var record = new LinkingRecord(this.symb.ProgramName); record.EntryName = line.Label; // set the location to the target of the RESET record.ProgramLocation = line.DirectiveOperand; this.AddRecord(record); } // store the rest in the report List<Errors.Error> errors = line.GetThreeErrors(); this.report.Add(null, null, ' ', line.SourceLineNumber, line.SourceLine, errors); continue; } // create the text record TextRecord rec = new TextRecord(this.symb.ProgramName); rec.ProgramLocation = line.ProgramCounter; rec.StatusFlag = 'A'; rec.Adjustments = "0"; string bin = line.Bytecode; // do we have an instruction? if (line.OpCategory != null) { // equated symbols may need to be relocated if (line.Equated != null) { Symbol symb = this.symb.GetSymbol(line.Equated); if (symb.relocations == 0) { rec.StatusFlag = 'A'; rec.Adjustments = "0"; } else if (symb.relocations == 1) { rec.StatusFlag = 'R'; rec.Adjustments = "0"; } else { ModificationRecord mod = new ModificationRecord(this.symb.ProgramName); mod.ProgramLocation = line.ProgramCounter; mod.Word = Convert.ToString(Convert.ToInt32(line.Bytecode, 2), 16); for (int i = 0; i < symb.relocations; i++) { mod.AddAdjustment(true, this.symb.ProgramName); } this.AddRecord(mod); rec.StatusFlag = 'M'; rec.Adjustments = Convert.ToString(symb.relocations, 16); } } // or a plain label else if (line.OpLitOperand == OperandParser.Literal.NONE) { // get the symbol that is being referenced if (line.OpOperand != null && this.symb.ContainsSymbol(line.OpOperand)) { Symbol symb = this.symb.GetSymbol(line.OpOperand); // external labels are processed in the linker if (symb.usage == Usage.EXTERNAL) { // create a modification record ModificationRecord mod = new ModificationRecord(this.symb.ProgramName); mod.ProgramLocation = line.ProgramCounter; mod.Word = Convert.ToString(Convert.ToInt32(line.Bytecode, 2), 16); mod.AddAdjustment(true, symb.rlabel); this.AddRecord(mod); // set the status to 1 modify rec.StatusFlag = 'M'; rec.Adjustments = "1"; } // otherwise we can resolve the symbol else { // get the binary encoding padded to 10 bits bin = BinaryHelper.BinaryString(symb.lc).PadLeft(10, '0'); // prefix it with the original instruction bytecode bin = line.Bytecode.Substring(0, 6) + bin; // relocatable label rec.StatusFlag = 'R'; } } // was it empty? else if (line.OpOperand == null || line.OpOperand.Length == 0) { bin = line.Bytecode; rec.StatusFlag = 'A'; } // error, otherwise else { line.AddError(Errors.Category.Serious, 34); line.NOPificate(); bin = line.Bytecode; } } // otherwise if it is (was) an expression else if (line.OpLitOperand == OperandParser.Literal.EXPRESSION) { // then is is relocatable // get the expression to be evaluated string expr = line.OpOperand; // create the modification record, this will have at least one // adjustment because these expressions are required to have a * ModificationRecord mod = new ModificationRecord(symb.ProgramName); // this is a garbage variable int rel; // evaluate the expression bool worked; worked = OperandParser.ParseExpression(ref expr, OperandParser.Expressions.Operand, line, ref symb, mod, out rel); if (worked) { // adjustments and such rec.StatusFlag = 'M'; rec.Adjustments = Convert.ToString(mod.Adjustments, 16); // get the hex sorted out int adj = Convert.ToInt32(expr, 16); int bytecode = Convert.ToInt32(bin, 2) + adj; // check the range int start = Convert.ToInt32(this.input.Line(1).DirectiveOperand, 16); int eof = start + Convert.ToInt32(this.input.ModuleLength, 16); if (Convert.ToInt32(expr, 16) > eof || Convert.ToInt32(expr, 16) < start) { line.AddError(Errors.Category.Serious, 38); line.NOPificate(); } else { bin = Convert.ToString(bytecode, 2); mod.Word = Convert.ToString(bytecode, 16); mod.ProgramLocation = line.ProgramCounter; this.AddRecord(mod); } } else { } } // special case: numeric values with GOTO, JUMP, MOPER else if (line.OpLitOperand == OperandParser.Literal.NUMBER && (line.OpFunction == "GOTO" || line.OpCategory == "JUMP" || line.OpCategory == "MOPER")) { rec.StatusFlag = 'R'; } // otherwise, it was a literal else { rec.StatusFlag = 'A'; } } // or a DAT directive? else if (line.Directive == "DAT") { // DAT fields shouldn't need to be modified rec.StatusFlag = 'A'; } // or an ADC directive? else if (line.Directive == "ADC" || line.Directive == "ADCE") { // make the modification record ModificationRecord mod = new ModificationRecord(symb.ProgramName); bool worked = true; string expr = line.DirectiveOperand; int rel = 0; int maxOp = 1; // this differentiates between ADC and ADCe if (line.Directive.EndsWith("E")) { maxOp = 3; } if (line.DirectiveLitOperand == OperandParser.Literal.EXPRESSION) { // wat do if expressions worked = OperandParser.ParseExpression(ref expr, OperandParser.Expressions.ADC, line, ref symb, mod, out rel, maxOp); // catching errors if (worked) { bin = Convert.ToString(Convert.ToInt32(expr, 16), 2); } } else if (line.DirectiveLitOperand == OperandParser.Literal.NUMBER) { // wat do if just a number mod.AddAdjustment(true, symb.ProgramName); rel = 1; bin = Convert.ToString(Convert.ToInt32(expr, 16), 2); } // check the range int start = Convert.ToInt32(this.input.Line(1).DirectiveOperand, 16); int eof = start + Convert.ToInt32(this.input.ModuleLength, 16); if (Convert.ToInt32(expr, 16) > eof || Convert.ToInt32(expr, 16) < start) { line.AddError(Errors.Category.Serious, 38); line.NOPificate(); bin = "0000000000000000"; } // if there are modifications to be made, add them if (mod.Adjustments > 0 && rel > 0 && worked) { rec.StatusFlag = 'M'; rec.Adjustments = Convert.ToString(mod.Adjustments, 16); mod.Word = Convert.ToString(Convert.ToInt32(bin, 2), 16); mod.ProgramLocation = line.ProgramCounter; this.AddRecord(mod); } } // anything else with a LC shouldn't be here... else { // this code *should* be unreachable throw new NotImplementedException(); } // convert bytecode to hex and add the record rec.HexCode = Convert.ToString(Convert.ToInt32(bin, 2), 16).ToUpper(); this.AddRecord(rec); // list of errors List<Errors.Error> errorlist = line.GetThreeErrors(); // add a line to the assembly report this.report.Add(line.ProgramCounter, rec.HexCode, rec.StatusFlag, line.SourceLineNumber, line.SourceLine, errorlist); } }
/** * Add a text record to this object file. * * @param record The text record to add * @refcode OB * @errtest * N/A * @errmsg * N/A * @author Jacob Peddicord * @creation May 10, 2011 * @modlog * @teststandard Andrew Buelow * @codestandard Mark Mathis */ private void AddRecord(TextRecord record) { this.textRecords.Add(record); }