コード例 #1
0
        public void SetTokens(GR.Collections.MultiMap <string, SymbolInfo> TokenInfo)
        {
            if (InvokeRequired)
            {
                Invoke(new SetTokensCallback(SetTokens), new object[] { TokenInfo });
                return;
            }

            comboSymbols.Items.Clear();

            GR.Collections.Set <string> keys = TokenInfo.GetUniqueKeys();
            foreach (var token in keys)
            {
                comboSymbols.Items.Add(token);
            }
            m_TokenInfos = TokenInfo;
        }
コード例 #2
0
ファイル: Project.cs プロジェクト: gonzoMD/C64Studio
        public GR.Collections.Set <FileDependency.DependencyInfo> GetDependencies(ProjectElement Element)
        {
            var dependencies = new GR.Collections.Set <FileDependency.DependencyInfo>();

            foreach (var dependency in Element.ForcedDependency.DependentOnFile)
            {
                if (!dependencies.ContainsValue(dependency))
                {
                    dependencies.Add(dependency);

                    ProjectElement otherElement = GetElementByFilename(dependency.Filename);
                    if (otherElement != null)
                    {
                        dependencies.Merge(GetDependencies(otherElement));
                    }
                }
            }
            return(dependencies);
        }
コード例 #3
0
 public SymbolInfo(SymbolInfo RHS)
 {
     Type             = RHS.Type;
     Name             = RHS.Name;
     LineIndex        = RHS.LineIndex; // global
     LineCount        = RHS.LineCount; // global (-1 is for complete file)
     DocumentFilename = RHS.DocumentFilename;
     LocalLineIndex   = RHS.LocalLineIndex;
     AddressOrValue   = RHS.AddressOrValue;
     String           = RHS.String;
     RealValue        = RHS.RealValue;
     Zone             = RHS.Zone;
     FromDependency   = RHS.FromDependency;
     Info             = RHS.Info;
     CharIndex        = RHS.CharIndex;
     Length           = RHS.Length;
     SourceInfo       = RHS.SourceInfo;
     References       = RHS.References;
 }
コード例 #4
0
        public string LabelsAsFile(LabelFileFormat Format)
        {
            StringBuilder sb = new StringBuilder();

            var sentLabels = new GR.Collections.Set <int>();

            foreach (var token in Labels)
            {
                if (token.Value.Type == SymbolInfo.Types.LABEL)
                {
                    switch (Format)
                    {
                    case LabelFileFormat.VICE:
                        // VICE now bails on values outside 16bit
                        if ((token.Value.AddressOrValue >= 0) &&
                            (token.Value.AddressOrValue <= 65535) &&
                            (!sentLabels.ContainsValue(token.Value.AddressOrValue)))
                        {
                            sentLabels.Add(token.Value.AddressOrValue);
                            sb.Append("add_label $");
                            sb.Append(token.Value.AddressOrValue.ToString("X4"));
                            sb.Append(" .");
                            sb.AppendLine(token.Key.Replace('.', '_').Replace('-', '_').Replace("+", "plus"));
                        }
                        break;

                    case LabelFileFormat.C64DEBUGGER:
                        sb.Append("al C:");
                        sb.Append(token.Value.AddressOrValue.ToString("X4"));
                        sb.Append(" .");
                        sb.AppendLine(token.Key.Replace('.', '_').Replace('-', '_').Replace("+", "plus"));
                        break;
                    }
                }
            }

            return(sb.ToString());
        }
コード例 #5
0
ファイル: D71.cs プロジェクト: wowjinxy/C64Studio
        public override void Validate()
        {
            var files = Files();

            GR.Collections.Set <GR.Generic.Tupel <int, int> > usedTracksAndSectors = new GR.Collections.Set <GR.Generic.Tupel <int, int> >();

            usedTracksAndSectors.Add(new GR.Generic.Tupel <int, int>(TRACK_HEADER, SECTOR_HEADER));
            usedTracksAndSectors.Add(new GR.Generic.Tupel <int, int>(TRACK_BAM, SECTOR_BAM));

            int curTrack  = TRACK_DIRECTORY;
            int curSector = SECTOR_DIRECTORY;

            usedTracksAndSectors.Add(new GR.Generic.Tupel <int, int>(curTrack, curSector));
            while (true)
            {
                Sector sec = Tracks[curTrack - 1].Sectors[curSector];

                curTrack  = sec.Data.ByteAt(0);
                curSector = sec.Data.ByteAt(1);

                if (curTrack == 0)
                {
                    // track = 0 marks last directory entry
                    break;
                }
                usedTracksAndSectors.Add(new GR.Generic.Tupel <int, int>(curTrack, curSector));
            }

            foreach (var file in files)
            {
                curTrack  = file.StartTrack;
                curSector = file.StartSector;

                while (true)
                {
                    Sector sec = Tracks[curTrack - 1].Sectors[curSector];

                    usedTracksAndSectors.Add(new GR.Generic.Tupel <int, int>(curTrack, curSector));

                    curTrack  = sec.Data.ByteAt(0);
                    curSector = sec.Data.ByteAt(1);

                    if (curTrack == 0)
                    {
                        // track = 0 marks last directory entry
                        break;
                    }
                }
            }
            foreach (var track in Tracks)
            {
                foreach (var sector in track.Sectors)
                {
                    if ((!sector.Free) &&
                        (!usedTracksAndSectors.ContainsValue(new GR.Generic.Tupel <int, int>(track.TrackNo, sector.SectorNo))))
                    {
                        sector.Free = true;
                    }
                }
            }
        }
コード例 #6
0
        private string MnemonicToString(Tiny64.Opcode opcode, GR.Memory.ByteBuffer Data, int DataStartAddress, int CodePos, GR.Collections.Set <ushort> AccessedAddresses, GR.Collections.Map <int, string> NamedLabels)
        {
            string output = opcode.Mnemonic.ToLower();

            ushort targetAddress = 0;
            bool   twoBytes      = true;

            switch (opcode.Addressing)
            {
            case Tiny64.Opcode.AddressingType.IMPLICIT:
                break;

            case Tiny64.Opcode.AddressingType.ABSOLUTE:
                targetAddress = Data.UInt16At(CodePos + 1 - DataStartAddress);
                break;

            case Tiny64.Opcode.AddressingType.ABSOLUTE_X:
                targetAddress = Data.UInt16At(CodePos + 1 - DataStartAddress);
                break;

            case Tiny64.Opcode.AddressingType.ABSOLUTE_Y:
                targetAddress = Data.UInt16At(CodePos + 1 - DataStartAddress);
                break;

            case Tiny64.Opcode.AddressingType.IMMEDIATE:
                targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress);
                twoBytes      = false;
                break;

            case Tiny64.Opcode.AddressingType.INDIRECT:
                targetAddress = Data.UInt16At(CodePos + 1 - DataStartAddress);
                break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE_INDIRECT_X:
                targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress);
                twoBytes      = false;
                break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE_INDIRECT_Y:
                targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress);
                twoBytes      = false;
                break;

            case Tiny64.Opcode.AddressingType.RELATIVE:
            {
                // int delta = value - lineInfo.AddressStart - 2;
                sbyte relValue = (sbyte)Data.ByteAt(CodePos + 1 - DataStartAddress);

                targetAddress = (ushort)(relValue + 2 + CodePos);
            }
            break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE:
                targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress);
                twoBytes      = false;
                break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE_X:
                targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress);
                twoBytes      = false;
                break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE_Y:
                targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress);
                twoBytes      = false;
                break;
            }
            string addressPlacement;

            if (twoBytes)
            {
                addressPlacement = "$" + targetAddress.ToString("x4");
            }
            else
            {
                addressPlacement = "$" + targetAddress.ToString("x2");
            }

            if (AccessedAddresses.ContainsValue(targetAddress))
            {
                addressPlacement = "label_" + targetAddress.ToString("x4");
            }

            if (NamedLabels.ContainsKey(targetAddress))
            {
                addressPlacement = NamedLabels[targetAddress];
            }

            switch (opcode.Addressing)
            {
            case Tiny64.Opcode.AddressingType.IMPLICIT:
                break;

            case Tiny64.Opcode.AddressingType.ABSOLUTE:
                output += " " + addressPlacement;
                break;

            case Tiny64.Opcode.AddressingType.ABSOLUTE_X:
                output += " " + addressPlacement + ", x";
                break;

            case Tiny64.Opcode.AddressingType.ABSOLUTE_Y:
                output += " " + addressPlacement + ", y";
                break;

            case Tiny64.Opcode.AddressingType.IMMEDIATE:
                output += " #" + addressPlacement;
                break;

            case Tiny64.Opcode.AddressingType.INDIRECT:
                output += " ( " + addressPlacement + " )";
                break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE_INDIRECT_X:
                output += " ( " + addressPlacement + ", x)";
                break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE_INDIRECT_Y:
                output += " ( " + addressPlacement + " ), y";
                break;

            case Tiny64.Opcode.AddressingType.RELATIVE:
            {
                // int delta = value - lineInfo.AddressStart - 2;

                output += " " + addressPlacement;
                //output += " (" + delta.ToString( "X2" ) + ")";
            }
            break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE:
                output += " " + addressPlacement;
                break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE_X:
                output += " " + addressPlacement + ", x";
                break;

            case Tiny64.Opcode.AddressingType.ZEROPAGE_Y:
                output += " " + addressPlacement + ", y";
                break;
            }
            return(output);
        }
コード例 #7
0
        public bool Disassemble(int DataStartAddress, GR.Collections.Set <int> JumpedAtAddresses, GR.Collections.Map <int, string> NamedLabels, DisassemblerSettings Settings, out string Disassembly, out int FirstLineWithOpcode)
        {
            StringBuilder sb = new StringBuilder();

            Disassembly         = "";
            FirstLineWithOpcode = 1;
            if (JumpedAtAddresses.Count == 0)
            {
                return(false);
            }

            int progStepPos = JumpedAtAddresses.First;

            GR.Collections.Set <ushort> accessedAddresses = new GR.Collections.Set <ushort>();
            GR.Collections.Set <int>    addressesToCheck  = new GR.Collections.Set <int>(JumpedAtAddresses);
            GR.Collections.Set <int>    addressesChecked  = new GR.Collections.Set <int>();
            GR.Collections.Set <ushort> probableLabel     = new GR.Collections.Set <ushort>();

            // check for basic header
            int sysAddress = -1;

            if (HasBASICJumpAddress(DataStartAddress, out sysAddress))
            {
                progStepPos = sysAddress;
                addressesToCheck.Add(progStepPos);
            }

            /*
             * else
             * {
             * // automatically check at data start address
             * addressesToCheck.Add( DataStartAddress );
             * }*/

            int codeStartPos = progStepPos;

            GR.Collections.Map <ushort, GR.Generic.Tupel <Tiny64.Opcode, ushort> > disassembly = new GR.Collections.Map <ushort, GR.Generic.Tupel <Tiny64.Opcode, ushort> >();

            while (addressesToCheck.Count > 0)
            {
                progStepPos = addressesToCheck.First;
                //Debug.Log( "check address:" + progStepPos );
                addressesToCheck.Remove(progStepPos);
                if (addressesChecked.ContainsValue(progStepPos))
                {
                    continue;
                }
                while (true)
                {
                    if (progStepPos < DataStartAddress)
                    {
                        break;
                    }

                    /*
                     * sb.Append( "Jumped to address before data\r\n" );
                     * Disassembly = sb.ToString();
                     * return false;
                     * }*/
                    if (progStepPos >= DataStartAddress + m_SourceData.Length)
                    {
                        // reached the end
                        break;
                    }

                    Tiny64.Opcode opcode      = null;
                    bool          outsideData = false;
                    if (!DisassembleInstruction(m_SourceData, DataStartAddress, progStepPos, out opcode, out outsideData))
                    {
                        if (!outsideData)
                        {
                            sb.Append("Failed to disassemble data $" + m_SourceData.ByteAt(progStepPos - DataStartAddress).ToString("X2") + " at location " + progStepPos + "($" + progStepPos.ToString("X4") + ")\r\n");
                            Disassembly = sb.ToString();
                            return(false);
                        }
                    }

                    if (outsideData)
                    {
                        break;
                    }

                    addressesChecked.Add(progStepPos);
                    //Debug.Log( "Mnemonic: " + OpcodeToString( opcode, Data, progStepPos + 1 - DataStartAddress ) );
                    //Debug.Log( progStepPos.ToString( "X4" ) + ": " + MnemonicToString( opcode, Data, DataStartAddress, progStepPos ) );

                    if ((opcode.ByteValue == 0x4c) || // jmp
                        (opcode.ByteValue == 0x20))   // jsr
                    {
                        // absolute jump
                        accessedAddresses.Add(m_SourceData.UInt16At(progStepPos + 1 - DataStartAddress));
                        addressesToCheck.Add(m_SourceData.UInt16At(progStepPos + 1 - DataStartAddress));
                        //Debug.Log( "access address " + Data.UInt16At( progStepPos + 1 ).ToString( "X4" ) );
                    }
                    else if (opcode.ByteValue == 0x6c) // jmp indirect
                    {
                        probableLabel.Add(m_SourceData.UInt16At(progStepPos + 1 - DataStartAddress));
                    }
                    else if (opcode.Addressing == Tiny64.Opcode.AddressingType.RELATIVE)
                    {
                        int targetAddress = (sbyte)m_SourceData.ByteAt(progStepPos + 1 - DataStartAddress) + 2 + progStepPos;
                        probableLabel.Add((ushort)targetAddress);
                        addressesToCheck.Add(targetAddress);
                        accessedAddresses.Add((ushort)targetAddress);
                    }

                    disassembly[(ushort)progStepPos] = new GR.Generic.Tupel <Tiny64.Opcode, ushort>(opcode, m_SourceData.UInt16At(progStepPos + 1));

                    if ((opcode.ByteValue == 0x40) || // rts
                        (opcode.ByteValue == 0x60) || // rti
                        (opcode.ByteValue == 0x4c))   // jmp
                    {
                        // end of code here
                        break;
                    }

                    //string output = MnemonicToString( opcode, Data, DataStartAddress, progStepPos );
                    //Debug.Log( output );
                    progStepPos += opcode.NumOperands + 1;
                }
            }

            progStepPos = codeStartPos;
            //foreach ( KeyValuePair<ushort,GR.Generic.Tupel<Opcode, ushort>> instruction in disassembly )

            // remove potential labels that are not in our code
            GR.Collections.Set <ushort> addressesToRemove = new GR.Collections.Set <ushort>();
            foreach (var accessedAddress in accessedAddresses)
            {
                if (!disassembly.ContainsKey(accessedAddress))
                {
                    addressesToRemove.Add(accessedAddress);
                }
            }
            foreach (var addressToRemove in addressesToRemove)
            {
                accessedAddresses.Remove(addressToRemove);
            }

            sb.Append("* = $");
            sb.AppendLine(DataStartAddress.ToString("x4"));

            if (!Settings.AddLineAddresses)
            {
                foreach (var namedLabel in NamedLabels)
                {
                    sb.Append(namedLabel.Value);
                    sb.Append(" = $");
                    sb.AppendLine(namedLabel.Key.ToString("X4"));
                }
                if (NamedLabels.Count > 0)
                {
                    sb.AppendLine();
                }
            }

            int  trueAddress    = DataStartAddress;
            bool hadBytes       = false;
            int  hadBytesStart  = 0;
            int  localLineIndex = 1;

            while (trueAddress < DataStartAddress + m_SourceData.Length)
            {
                if (disassembly.ContainsKey((ushort)trueAddress))
                {
                    if (hadBytes)
                    {
                        sb.Append(DisassembleBinary(m_SourceData, DataStartAddress, hadBytesStart, trueAddress - hadBytesStart, Settings));
                        hadBytes = false;
                    }
                    GR.Generic.Tupel <Tiny64.Opcode, ushort> instruction = disassembly[(ushort)trueAddress];
                    if (Settings.AddLineAddresses)
                    {
                        sb.Append("$");
                        sb.Append(trueAddress.ToString("X4") + ": ");
                    }

                    if (DataStartAddress == trueAddress)
                    {
                        FirstLineWithOpcode = localLineIndex;
                    }
                    ++localLineIndex;


                    if (accessedAddresses.ContainsValue((ushort)trueAddress))
                    {
                        // line break in front of named label
                        sb.AppendLine();
                        if (Settings.AddLineAddresses)
                        {
                            sb.Append("$");
                            sb.Append(trueAddress.ToString("X4") + ": ");
                        }

                        if (NamedLabels.ContainsKey(trueAddress))
                        {
                            sb.AppendLine(NamedLabels[trueAddress]);
                        }
                        else
                        {
                            sb.Append("label_" + trueAddress.ToString("x4") + "\r\n");
                        }
                        if (Settings.AddLineAddresses)
                        {
                            sb.Append("$");
                            sb.Append(trueAddress.ToString("X4") + ": ");
                        }
                    }
                    else if (NamedLabels.ContainsKey(trueAddress))
                    {
                        // line break in front of named label
                        sb.AppendLine();
                        if (Settings.AddLineAddresses)
                        {
                            sb.Append("$");
                            sb.Append(trueAddress.ToString("X4") + ": ");
                        }

                        sb.AppendLine(NamedLabels[trueAddress]);
                        if (Settings.AddLineAddresses)
                        {
                            sb.Append("$");
                            sb.Append(trueAddress.ToString("X4") + ": ");
                        }
                    }

                    if (Settings.AddAssembledBytes)
                    {
                        sb.Append(" ");
                        sb.Append(instruction.first.ByteValue.ToString("X2"));

                        switch (instruction.first.NumOperands)
                        {
                        case 0:
                            sb.Append("      ");
                            break;

                        case 1:
                            sb.Append(" ");
                            sb.Append(m_SourceData.ByteAt(trueAddress + 1 - DataStartAddress).ToString("X2"));
                            sb.Append("   ");
                            break;

                        case 2:
                            sb.Append(" ");
                            sb.Append(m_SourceData.ByteAt(trueAddress + 1 - DataStartAddress).ToString("X2"));
                            sb.Append(" ");
                            sb.Append(m_SourceData.ByteAt(trueAddress + 1 - DataStartAddress + 1).ToString("X2"));
                            break;
                        }
                    }
                    sb.Append("   " + MnemonicToString(instruction.first, m_SourceData, DataStartAddress, trueAddress, accessedAddresses, NamedLabels));
                    sb.Append("\r\n");
                    trueAddress += instruction.first.NumOperands + 1;
                }
                else
                {
                    if (!hadBytes)
                    {
                        hadBytes      = true;
                        hadBytesStart = trueAddress;
                    }
                    ++trueAddress;
                }
            }
            if (hadBytes)
            {
                sb.Append(DisassembleBinary(m_SourceData, DataStartAddress, hadBytesStart, trueAddress - hadBytesStart, Settings));
                hadBytes = false;
            }
            Disassembly = sb.ToString();
            return(true);
        }
コード例 #8
0
        public int ImageToMCBitmapData(Dictionary <int, List <ColorMappingTarget> > ForceBitPattern, List <Formats.CharData> Chars, bool[,] ErrornousBlocks, int CharX, int CharY, int WidthChars, int HeightChars, out GR.Memory.ByteBuffer bitmapData, out GR.Memory.ByteBuffer screenChar, out GR.Memory.ByteBuffer screenColor)
        {
            int numErrors = 0;

            ColorMappingTarget[] bitPattern = new ColorMappingTarget[3] {
                ColorMappingTarget.BITS_01, ColorMappingTarget.BITS_10, ColorMappingTarget.BITS_11
            };
            var usedBitPattern = new GR.Collections.Set <ColorMappingTarget>();

            Dictionary <int, GR.Collections.Set <ColorMappingTarget> > usedPatterns = new Dictionary <int, GR.Collections.Set <ColorMappingTarget> >();

            screenChar  = new GR.Memory.ByteBuffer((uint)(WidthChars * HeightChars));
            screenColor = new GR.Memory.ByteBuffer((uint)(WidthChars * HeightChars));
            bitmapData  = new GR.Memory.ByteBuffer((uint)(8 * WidthChars * HeightChars));

            GR.Collections.Map <byte, ColorMappingTarget> usedColors = new GR.Collections.Map <byte, ColorMappingTarget>();

            for (int y = 0; y < HeightChars; ++y)
            {
                for (int x = 0; x < WidthChars; ++x)
                {
                    // ein zeichen-block
                    usedColors.Clear();
                    usedBitPattern.Clear();
                    if (ErrornousBlocks != null)
                    {
                        ErrornousBlocks[x, y] = false;
                    }
                    for (int charY = 0; charY < 8; ++charY)
                    {
                        for (int charX = 0; charX < 4; ++charX)
                        {
                            byte colorIndex = (byte)Image.GetPixel(x * 8 + charX * 2, y * 8 + charY);
                            if (colorIndex >= 16)
                            {
                                if (Chars != null)
                                {
                                    Chars[x + y * BlockWidth].Error = "Color index >= 16 (" + colorIndex + ") at " + (x * 8 + charX * 2).ToString() + ", " + (y * 8 + charY).ToString() + " (" + charX + "," + charY + ")";
                                }
                                if (ErrornousBlocks != null)
                                {
                                    ErrornousBlocks[x, y] = true;
                                }
                                ++numErrors;
                            }
                            if (colorIndex != Colors.BackgroundColor)
                            {
                                // remember used color
                                usedColors.Add(colorIndex, 0);
                            }
                        }
                    }
                    // more than 3 colors?
                    if (usedColors.Count > 3)
                    {
                        if (Chars != null)
                        {
                            Chars[x + y * BlockWidth].Error = "Too many colors used";
                        }
                        if (ErrornousBlocks != null)
                        {
                            ErrornousBlocks[x, y] = true;
                        }
                        ++numErrors;
                    }
                    else
                    {
                        if (usedColors.Count > 0)
                        {
                            int         colorTarget = 0;
                            List <byte> keys        = new List <byte>(usedColors.Keys);

                            // check for overlaps - two colors are used that would map to the same target pattern?
                            Dictionary <int, ColorMappingTarget> recommendedPattern = new Dictionary <int, ColorMappingTarget>();

                            numErrors += DetermineBestMapping(keys, x, y, ForceBitPattern, recommendedPattern, ErrornousBlocks);

                            foreach (byte colorIndex in keys)
                            {
                                if (recommendedPattern.ContainsKey(colorIndex))
                                {
                                    usedColors[colorIndex] = recommendedPattern[colorIndex];

                                    if (!usedPatterns.ContainsKey(colorIndex))
                                    {
                                        usedPatterns.Add(colorIndex, new GR.Collections.Set <ColorMappingTarget>());
                                    }
                                    usedPatterns[colorIndex].Add(recommendedPattern[colorIndex]);
                                    usedBitPattern.Add(recommendedPattern[colorIndex]);

                                    switch (recommendedPattern[colorIndex])
                                    {
                                    case ColorMappingTarget.BITS_01:
                                    {
                                        // upper screen char nibble
                                        byte value = screenChar.ByteAt(x + y * WidthChars);
                                        value &= 0x0f;
                                        value |= (byte)(colorIndex << 4);

                                        screenChar.SetU8At(x + y * WidthChars, value);
                                    }
                                    break;

                                    case ColorMappingTarget.BITS_10:
                                    {
                                        // lower nibble in screen char
                                        byte value = screenChar.ByteAt(x + y * WidthChars);
                                        value &= 0xf0;
                                        value |= (byte)(colorIndex);

                                        screenChar.SetU8At(x + y * WidthChars, value);
                                    }
                                    break;

                                    case ColorMappingTarget.BITS_11:
                                        // color ram
                                        screenColor.SetU8At(x + y * WidthChars, colorIndex);
                                        break;
                                    }
                                    continue;
                                }

                                if (!usedPatterns.ContainsKey(colorIndex))
                                {
                                    usedPatterns.Add(colorIndex, new GR.Collections.Set <ColorMappingTarget>());
                                }
                                usedPatterns[colorIndex].Add(bitPattern[colorTarget]);

                                colorTarget = 0;
                                while ((colorTarget < 3) &&
                                       (usedBitPattern.ContainsValue(bitPattern[colorTarget])))
                                {
                                    ++colorTarget;
                                }
                                usedBitPattern.Add(bitPattern[colorTarget]);

                                if (colorTarget == 0)
                                {
                                    // upper screen char nibble
                                    byte value = screenChar.ByteAt(x + y * WidthChars);
                                    value &= 0x0f;
                                    value |= (byte)(colorIndex << 4);

                                    screenChar.SetU8At(x + y * WidthChars, value);
                                    usedColors[colorIndex] = ColorMappingTarget.BITS_01;
                                }
                                else if (colorTarget == 1)
                                {
                                    // lower nibble in screen char
                                    byte value = screenChar.ByteAt(x + y * WidthChars);
                                    value &= 0xf0;
                                    value |= (byte)(colorIndex);

                                    screenChar.SetU8At(x + y * WidthChars, value);
                                    usedColors[colorIndex] = ColorMappingTarget.BITS_10;
                                }
                                else if (colorTarget == 2)
                                {
                                    // color ram
                                    screenColor.SetU8At(x + y * WidthChars, colorIndex);
                                    usedColors[colorIndex] = ColorMappingTarget.BITS_11;
                                }
                                ++colorTarget;
                            }
                        }
                        // write out bits

                        /*
                         * Debug.Log( "For Char " + x + "," + y );
                         * foreach ( var usedColor in usedColors )
                         * {
                         * Debug.Log( " Color " + usedColor.Key + " = " + usedColor.Value );
                         * }*/
                        for (int charY = 0; charY < 8; ++charY)
                        {
                            for (int charX = 0; charX < 4; ++charX)
                            {
                                byte colorIndex = (byte)Image.GetPixel(x * 8 + charX * 2, y * 8 + charY);
                                if (colorIndex != Colors.BackgroundColor)
                                {
                                    // other color
                                    byte colorValue = 0;

                                    switch (usedColors[colorIndex])
                                    {
                                    case ColorMappingTarget.BITS_01:
                                        colorValue = 0x01;
                                        break;

                                    case ColorMappingTarget.BITS_10:
                                        colorValue = 0x02;
                                        break;

                                    case ColorMappingTarget.BITS_11:
                                        colorValue = 0x03;
                                        break;
                                    }
                                    int bitmapIndex = x * 8 + y * 8 * WidthChars + charY;

                                    byte value = bitmapData.ByteAt(bitmapIndex);
                                    if (charX == 0)
                                    {
                                        value &= 0x3f;
                                        value |= (byte)(colorValue << 6);
                                    }
                                    else if (charX == 1)
                                    {
                                        value &= 0xcf;
                                        value |= (byte)(colorValue << 4);
                                    }
                                    else if (charX == 2)
                                    {
                                        value &= 0xf3;
                                        value |= (byte)(colorValue << 2);
                                    }
                                    else
                                    {
                                        value &= 0xfc;
                                        value |= colorValue;
                                    }
                                    bitmapData.SetU8At(bitmapIndex, value);
                                }
                            }
                        }
                    }
                }
            }

            /*
             * Debug.Log( "Used patterns:" );
             * foreach ( var entry in usedPatterns )
             * {
             * Debug.Log( "Index " + entry.Key );
             * foreach ( var pattern in entry.Value )
             * {
             *  Debug.Log( " used " + pattern );
             * }
             * }*/
            return(numErrors);
        }