Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }