public static InstructionSet Load(string definition) { string[] lines = definition.Replace("\r", "").Split('\n'); var table = new InstructionSet(); for (int i = 0; i < lines.Length; i++) { string line = lines[i].Trim(); if (line.StartsWith("#") || string.IsNullOrEmpty(line)) { continue; } line = line.RemoveExcessWhitespace(); if (line.StartsWith("OPERAND ")) { string[] parts = line.Split(' '); var operand = new Operand(parts[2], parts[3]); if (!table.OperandGroups.ContainsKey(parts[1])) { table.OperandGroups.Add(parts[1], new OperandGroup(parts[1])); } table.OperandGroups[parts[1]].Operands.Add(operand); } else if (line.StartsWith("INS ")) { string[] parts = line.Split(' '); string match = parts[1]; string value = line.Substring(line.IndexOf(' ') + 1); value = value.Substring(value.IndexOf(' ') + 1); table.Instructions.Add(new Instruction(match.ToLower(), value.Replace(" ", ""))); } else if (line.StartsWith("WORDSIZE ")) { table.WordSize = int.Parse(line.Substring(9)); } else { throw new FormatException("In the instruction set, \"" + line + "\" is not valid."); } } return(table); }
public static int Main(string[] args) { InstructionSets = new Dictionary <string, InstructionSet>(); InstructionSets.Add("z80", LoadInternalSet("sasSX.Tables.z80.table")); InstructionSets.Add("z80alt", LoadInternalSet("sasSX.Tables.z80alt.table")); string instructionSet = "z80"; // Default string inputFile = null, outputFile = null; settings = new AssemblySettings(); List <string> defines = new List <string>(); Console.WriteLine("-------------------------------------------------------------------------------"); Console.WriteLine("sasSX v" + version + " WIP MSX cross-assembler.KnightOS [2015],Libertium Games[2016/07/30]"); Console.WriteLine("-------------------------------------------------------------------------------"); // Assembling labels, calls and jumps // Output text file game.txt saved // Binary file game.rom saved // Symbol file game.sym saved // Completed in 1.07 seconds for (int i = 0; i < args.Length; i++) { string arg = args[i]; if (arg.StartsWith("-") && arg != "-") { try { switch (arg) { case "-d": case "--define": defines.AddRange(args[++i].Split(',')); break; case "--debug-mode": Thread.Sleep(10000); break; case "--encoding": try { settings.Encoding = Encoding.GetEncoding(args[++i]); } catch { Console.Error.WriteLine( "The specified encoding was not recognized. Use sasSX --list-encodings to see available encodings."); return(1); } break; case "-h": case "-?": case "/?": case "/help": case "-help": case "--help": DisplayHelp(); return(0); case "--inc": case "--include": settings.IncludePath = args[++i].Split(';'); break; case "--input": case "--input-file": inputFile = args[++i]; break; case "--instr": case "--instruction-set": instructionSet = args[++i]; break; case "-as": case "--asmsx": instructionSet = "z80alt"; asmsx = true; break; case "-l": case "--listing": if (i <= arg.Length && !args[i + 1].StartsWith("-")) { settings.ListingOutput = args[++i]; } else { Console.WriteLine("!!--listing whithout parameter !!"); } break; case "--list-encodings": Console.WriteLine("The default encoding is UTF-8. The following are available: "); foreach (var encoding in Encoding.GetEncodings()) { Console.WriteLine("{0} [{1}]", encoding.DisplayName, encoding.Name); } Console.WriteLine("Use the identifier (in [brackets]) with --encoding)."); return(0); case "--nest-macros": settings.AllowNestedMacros = true; break; case "--output": case "--output-file": outputFile = args[++i]; break; case "-s": case "--symbols": if (i <= arg.Length && !args[i + 1].StartsWith("-")) { settings.SymbolOutput = args[++i]; } else { settings.SymbolOutput = ""; } break; case "-v": case "--verbose": settings.Verbose = VerboseLevels.Minimal; if (i + 1 < args.Length && !args[i + 1].StartsWith("-")) { int level = 0; Int32.TryParse(args[++i], out level); settings.Verbose = (VerboseLevels)level; } //settings.Verbose = VerboseLevel; Console.WriteLine("Verbose level: {0}", settings.Verbose); break; } } catch (ArgumentOutOfRangeException) { Console.Error.WriteLine("Error: Invalid usage. Use sasSX.exe --help for usage information."); return(1); } } else { if (inputFile == null) { inputFile = args[i]; } else if (outputFile == null) { outputFile = args[i]; } else { Console.Error.WriteLine("Error: Invalid usage. Use sasSX.exe --help for usage information."); return(1); } } } if (inputFile == null) { Console.Error.WriteLine("Syntax: sasSX [file.asm]"); Console.Error.WriteLine("No input file specified. Use sasSX.exe --help for usage information."); return(1); } if (outputFile == null) { outputFile = Path.GetFileNameWithoutExtension(inputFile) + ".bin"; } InstructionSet selectedInstructionSet; if (!InstructionSets.ContainsKey(instructionSet)) { if (File.Exists(instructionSet)) { selectedInstructionSet = InstructionSet.Load(File.ReadAllText(instructionSet)); } else { Console.Error.WriteLine("Specified instruction set was not found."); return(1); } } else { selectedInstructionSet = InstructionSets[instructionSet]; } var assembler = new Assembler(selectedInstructionSet, settings); assembler.ASMSX = asmsx; foreach (var define in defines) { assembler.ExpressionEngine.Symbols.Add(define.ToLower(), new Symbol(1)); } string file = ""; if (inputFile == "-") { file = Console.In.ReadToEnd(); } else if (File.Exists(inputFile)) { file = File.ReadAllText(inputFile); } else { Console.Error.WriteLine("File not found: {0}", inputFile); Console.Error.WriteLine("Press any key to continue..."); Console.ReadKey(true); } var watch = new Stopwatch(); AssemblyOutput output = null; if (file != "") { Console.WriteLine("Assembling labels, calls and jumps"); VerboseLevels v = settings.Verbose; watch.Start(); output = assembler.Assemble(file, inputFile); //watch.Stop (); if (settings.Verbose != v) { Console.WriteLine("Verbose level from .asm: {0}", settings.Verbose); } var errors = from l in output.Listing where l.Warning != AssemblyWarning.None || l.Error != AssemblyError.None orderby l.RootLineNumber select l; if (settings.Verbose == VerboseLevels.Quiet || settings.Verbose == VerboseLevels.Diagnostic) //!settings.Verbose) { foreach (var listing in errors) { if (listing.Error != AssemblyError.None) { //Console.Error.WriteLine (listing.FileName + ":" + listing.LineNumber + " Error: " + listing.Error +". Code: " + listing.Code); Console.Error.WriteLine(listing.FileName + " " + listing.LineNumber + " " + listing.Code + " : " + listing.Error); } // Cesc if (settings.Verbose == VerboseLevels.Diagnostic && listing.Warning != AssemblyWarning.None) { Console.Error.WriteLine(listing.FileName + ":" + listing.LineNumber + " Warning: " + listing.Warning + ". Code: " + listing.Code); } } } if (settings.ListingOutput != null || (settings.Verbose != VerboseLevels.Quiet && settings.Verbose != VerboseLevels.Diagnostic)) { var listing = GenerateListing(output); if (settings.Verbose != VerboseLevels.Quiet && settings.Verbose != VerboseLevels.Minimal) { Console.Write(listing); } if (settings.ListingOutput != null) { File.WriteAllText(settings.ListingOutput, listing); Console.WriteLine("Output text file " + settings.ListingOutput + " saved"); } } if (settings.SymbolOutput != null) { if (settings.SymbolOutput == "") { settings.SymbolOutput = inputFile.ToLower().Replace(".asm", ".sym"); } using (var symbolWriter = new StreamWriter(settings.SymbolOutput)) { symbolWriter.WriteLine("; This symbol table file was generated from {0}", inputFile); symbolWriter.WriteLine("; sasSX Version " + version); symbolWriter.WriteLine(); symbolWriter.WriteLine("; global and local labels"); WriteSymbols(assembler, symbolWriter); Console.WriteLine("Symbols file " + settings.SymbolOutput + " saved"); } } // Cesc: todo pendent de validar amb casos de prova i en especial les ROM de 48KB if (assembler.IsROM) { // Sizes: 16KB to 48KB in steps of 16KB int pages = 8; // TODO Default 32KB int size = pages * 16 * 1024; // Default 128KB byte[] rom = setROMHeader(size, assembler.ROMStart); int srcAdress = 0; foreach (Assembler.ORGItem item in assembler.ORGsList) { if (settings.Verbose == VerboseLevels.Diagnostic) { Console.WriteLine("ORG: 0x{0:X}-0x{1:X} Subpage:{2}", item.ORGAdress, item.ORGLength, item.Subpage); } uint orgIni; if (srcAdress == 0) { orgIni = item.ORGAdress - 0x4000 + 16; } else { orgIni = item.ORGAdress - 0x4000; } if (item.ORGAdress < 0xc000) { for (uint i = orgIni; i < (item.ORGLength - 0x4000); i++) { rom [i] = output.Data [srcAdress]; srcAdress++; } } } File.WriteAllBytes(outputFile.Replace(".bin", ".rom"), rom); } else if (assembler.IsMegaROM) { // Sizes: 128KB to 512KB in steps of 8KB int pages = 0; // Default 128KB foreach (Assembler.ORGItem item in assembler.ORGsList) { pages = (int)Math.Max(pages, item.Subpage); if (settings.Verbose == VerboseLevels.Diagnostic) { Console.WriteLine("ORG: 0x{0:X}-0x{1:X} Subpage:{2}", item.ORGAdress, item.ORGLength, item.Subpage); } } pages++; if (settings.Verbose == VerboseLevels.Diagnostic) { Console.WriteLine("Pages count:{0}", pages); } if (errors.Count(e => e.Error != AssemblyError.None) == 0) { byte[] rom = fillMegaROM(pages, assembler, output); File.WriteAllBytes(outputFile.Replace(".bin", ".rom"), rom); Console.WriteLine("Binary file " + outputFile.Replace(".bin", ".rom") + " saved"); if (settings.Verbose == VerboseLevels.Diagnostic) { File.WriteAllBytes(outputFile, output.Data); Console.WriteLine("Binary file " + outputFile + " saved"); } } else { Console.WriteLine("Errors count:{0}", errors.Count(e => e.Error != AssemblyError.None)); } } else { if (outputFile == "-") { Console.OpenStandardOutput().Write(output.Data, 0, output.Data.Length); } else { File.WriteAllBytes(outputFile, output.Data); } } watch.Stop(); Console.Error.WriteLine("Assembly done: {0:F2} s", watch.ElapsedMilliseconds / 1000d); if (Debugger.IsAttached) { Console.Error.WriteLine("Press any key to continue..."); Console.ReadKey(true); } return(errors.Count(e => e.Error != AssemblyError.None)); } return(-1); }