예제 #1
0
        /// <summary>
        /// Generates the code for the desired effect
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="table"></param>
        /// <param name="sa1"></param>
        /// <returns></returns>
        public override string Code(int channel, HDMATable table, bool sa1)
        {
            int Base        = 0x4300 + (channel * 0x10);
            int Register    = (int)Layers;
            int BaseAddress = RAM.Layer1X[sa1] + ((int)Layers - (int)LayerRegister.Layer1_X) * 2;
            int RegMode     = ((Register & 0xFF) << 8) + 0x02;
            int LSRs        = (int)((1.0 / _speed) / 2.0);

            int Tablesize  = (Scanlines / _width) >= 15 ? 15 : (Scanlines / _width);
            int TableInRAM = CountRAMBytes();

            string tableString = "The Table takes up " + TableInRAM + " bytes of the free RAM\n" +
                                 "It ranges from $" + FreeRAM.ToString("X6") + " - $" + (FreeRAM + TableInRAM - 1).ToString("X6") + " (both addresses included)";

            ASMTable codeTable = new ASMTable(".WaveTable");

            for (int i = 0; i <= Tablesize; i++)
            {
                codeTable.Add(new ASMTableEntry((byte)_IArr[i]));
            }

            char xy = (((int)Layers & 0x01) == 0 ? 'Y' : 'X');

            ASMCodeBuilder CodeBuilder = new ASMCodeBuilder();

            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(INITLabel, "This section is to be used in the INIT code of levelASM");
            CodeBuilder.AppendCode("REP #$20");
            CodeBuilder.AppendCode("LDA #$" + RegMode.ToASMString(), "Use Mode 02 on register " + Register.ToASMString());
            CodeBuilder.AppendCode("STA $" + Base.ToASMString(), "43" + Channel + "0 = Mode, 43" + Channel + "1 = Register");
            CodeBuilder.AppendCode("LDA #$" + (FreeRAM & 0xFFFF).ToASMString(), "Address of HDMA table");
            CodeBuilder.AppendCode("STA $" + (Base + 2).ToASMString(), "43" + Channel + "2 = Low-Byte of table, 43" + Channel + "3 = High-Byte of table");
            CodeBuilder.AppendCode("SEP #$20");
            CodeBuilder.AppendCode("LDA.b #$" + (FreeRAM >> 16).ToASMString(), "Address of HDMA table, get bank byte");
            CodeBuilder.AppendCode("STA $" + (Base + 4).ToASMString(), "43" + Channel + "4 = Bank-Byte of table");
            CodeBuilder.AppendCode("LDA #$" + (0x01 << Channel).ToASMString());
            CodeBuilder.AppendCode("TSB $" + RAM.HDMAEnable[sa1].ToASMString(), "Enable HDMA channel " + Channel);
            CodeBuilder.AppendCode("RTS", "End HDMA setup" + MAINSeperator);
            CodeBuilder.CloseBlock();


            CodeBuilder.AppendCommentLine(tableString);
            CodeBuilder.AppendEmptyLine();

            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(MAINLabel, "This section is to be used in the MAIN code of levelASM");
            CodeBuilder.AppendCode("LDY #$00", "Y will be the loop counter.");
            CodeBuilder.AppendCode("LDX #$00", "X the index for writing the table to the RAM");
            CodeBuilder.AppendCode("LDA $" + RAM.FrameCounter[sa1].ToASMString(), "Speed of waves");
            CodeBuilder.AppendCode("LSR #" + LSRs, "Slowing down A");
            CodeBuilder.AppendCode("STA $00", "Save for later use.");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendCode("PHB : PHK : PLB", "Preservev bank");
            CodeBuilder.AppendLabel(".Loop", "Jump back if not finished writing table");
            CodeBuilder.AppendCode("LDA #$" + _width.ToASMString(), "Set scanline height");
            CodeBuilder.AppendCode("STA $" + FreeRAM.ToASMString() + ",x", "for each wave");
            CodeBuilder.AppendCode("TYA", "Transfer Y to A, to calculate next index");
            CodeBuilder.AppendCode("ADC $00", "Add frame counter");
            CodeBuilder.AppendCode("AND #$" + Tablesize.ToASMString());
            CodeBuilder.AppendCode("PHY", "Preserve loop counter");
            CodeBuilder.AppendCode("TAY", "Get the index in Y");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendCode("LDA.w " + codeTable.Name + ",y", "Load in wave value");
            CodeBuilder.AppendCode("LSR", "Half only");
            CodeBuilder.AppendCode("CLC", "Clear Carry for addition");
            CodeBuilder.AppendCode("ADC $" + (BaseAddress).ToASMString(), "Add value to layer " + xy + " position (low byte)");
            CodeBuilder.AppendCode("STA $" + (FreeRAM + 1).ToASMString() + ",x", "store to HDMA table (low byte)");
            CodeBuilder.AppendCode("LDA $" + (BaseAddress + 1).ToASMString(), "Get high byte of X position");
            CodeBuilder.AppendCode("ADC #$00", "Add value to layer X position (low byte)");
            CodeBuilder.AppendCode("STA $" + (FreeRAM + 2).ToASMString() + ",x", "store to HDMA table (high byte)");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendCode("PLY", "Pull original loop counter");
            CodeBuilder.AppendCode("CPY #$" + (Scanlines / _width).ToASMString(), "Compare if we have written enough HDMA entries.");
            CodeBuilder.AppendCode("BPL .End", "If bigger, end HDMA");
            CodeBuilder.AppendCode("INX", "Increase X, so that in the next loop, it writes the new table data...");
            CodeBuilder.AppendCode("INX", "... at the end of the old one instead of overwritting it.");
            CodeBuilder.AppendCode("INX");
            CodeBuilder.AppendCode("INY", "Increase loop counter");
            CodeBuilder.AppendCode("BRA .Loop", "Repeat loop");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(".End", "Jump here when at the end of HDMA");
            CodeBuilder.AppendCode("PLB", "Pull back data bank.");
            CodeBuilder.AppendCode("LDA #$00", "End HDMA by writting 00...");
            CodeBuilder.AppendCode("STA $" + (FreeRAM + 3).ToASMString() + ",x", "...at the end of the table.");
            CodeBuilder.AppendCode("RTS");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendTable(codeTable);
            CodeBuilder.CloseBlock();

            return(CodeBuilder.ToString());           // +"\n\n" + tableString;
        }
예제 #2
0
        public override string Code(int channel, HDMATable table, bool sa1)
        {
            int Base        = 0x4300 + (channel * 0x10);
            int Register    = (int)Layers;
            int BaseAddress = RAM.Layer1X[sa1] + ((int)Layers - (int)LayerRegister.Layer1_X) * 2;
            int RegMode     = ((Register & 0xFF) << 8) + GetMode(true, DMAMode.PP);

            var       grouped    = Bars.GroupBy(b => b.Multiplier);
            HDMATable _table     = new HDMATable("ParallaxTable_" + DateTime.Now.ToString("HHmmssfff"));
            int       tableInRAM = grouped.Count() * 2;

            Dictionary <int, int> multiplierAddressMapping = new Dictionary <int, int>();
            int addresseForOne = 0;             //address that has the scrollrate of 1 to finish the table.


            string tableString = "The Table takes up " + tableInRAM + " bytes of the free RAM\n" +
                                 "It ranges from $" + FreeRAM.ToString("X6") + " - $" + (FreeRAM + tableInRAM - 1).ToString("X6") + " (both addresses included)";

            ASMCodeBuilder CodeBuilder = new ASMCodeBuilder();

            if (Original.Height > Scanlines)
            {
                CodeBuilder.AppendCommentLine("IMPORTANT! Please edit the JMP command below for the level you use this on");
            }
            CodeBuilder.AppendEmptyLine();

            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(INITLabel, "This section is to be used in the INIT code of levelASM");
            CodeBuilder.AppendCode("REP #$20");
            CodeBuilder.AppendCode("LDA #$" + RegMode.ToASMString(), "Use indeirect and mode " + (int)DMAMode.PP + " on register " + Register.ToASMString());
            CodeBuilder.AppendCode("STA $" + Base.ToASMString(), "43" + Channel + "0 = Mode, 43" + Channel + "1 = Register");

            if (Original.Height <= Scanlines)
            {
                CodeBuilder.AppendCode("LDA #" + _table.Name, "Address of HDMA table, get high and low byte");
                CodeBuilder.AppendCode("STA $" + (Base + 2).ToASMString(), "43" + Channel + "2 = Low-Byte of table, 43" + Channel + "3 = High-Byte of table");
            }

            CodeBuilder.AppendCode("SEP #$20");
            CodeBuilder.AppendCode("LDA.b #" + _table.Name + ">>16", "Address of HDMA table, get bank byte");
            CodeBuilder.AppendCode("STA $" + (Base + 4).ToASMString(), "43" + Channel + "4 = Bank-Byte of table");

            CodeBuilder.AppendCode("LDA #$" + (FreeRAM >> 16).ToASMString(), "Address of indirect table in RAM bank byte");
            CodeBuilder.AppendCode("STA $" + (Base + 7).ToASMString(), "43" + Channel + "4 = Bank-Byte of indirect table");

            CodeBuilder.AppendCode("LDA #$" + (0x01 << Channel).ToASMString());
            CodeBuilder.AppendCode("TSB $" + RAM.HDMAEnable[sa1].ToASMString() + "|!addr", "Enable HDMA channel " + Channel);

            if (Original.Height > Scanlines)
            {
                CodeBuilder.AppendCode("JMP level105_" + MAINLabel.TrimStart('.'), "Jump to main code" + MAINSeperator);
            }
            else
            {
                CodeBuilder.AppendCode("RTL", "Return" + MAINSeperator);
            }
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendCommentLine(tableString);
            CodeBuilder.AppendEmptyLine();

            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(MAINLabel, "This section is to be used in the MAIN code of levelASM");
            CodeBuilder.AppendCode("REP #$20", "16 bit action starts here. (To load the x position of the BG)");
            CodeBuilder.CloseBlock();

            //index for HDMA table entry calculation
            if (Original.Height > Scanlines)
            {
                CodeBuilder.OpenNewBlock();
                CodeBuilder.AppendCode("LDA $" + (BaseAddress + 2).ToASMString(), "Get Y position of BG");
                CodeBuilder.AppendCode("ASL", "times 2");
                CodeBuilder.AppendCode("CLC : ADC $" + (BaseAddress + 2).ToASMString(), "+1 = times 3");
                CodeBuilder.AppendCode("CLC : ADC #" + _table.Name + "+3", "plus Address of HDMA table +3");
                //CodeBuilder.AppendCode("INC : INC : INC", "I have no idea why, but the result is off by 1 entry (3 bytes) so this is to fix it.");
                CodeBuilder.AppendCode("STA $" + (Base + 2).ToASMString(), "43" + Channel + "2 = Low-Byte of table, 43" + Channel + "3 = High-Byte of table");
                CodeBuilder.CloseBlock();
            }

            CodeBuilder.AppendEmptyLine();
            int i = 0;

            //grouped by multiplier
            foreach (var bar in grouped)
            {
                CodeBuilder.OpenNewBlock();
                if (bar.Key != 0.0)
                {
                    CodeBuilder.AppendCode("LDA $" + BaseAddress.ToASMString(), "Load BG x Position");
                }
                CodeBuilder.AppendCode(ParallaxHDMAEntry.LsrAsl(bar.Key), "Multiplied by " + bar.Key);
                var windGroup = bar.GroupBy(b => b.Autospeed);

                foreach (var singleBar in windGroup)
                {
                    //if there is no wind, don't add or preserve A
                    if (singleBar.ElementAt(0).Autoscroll&& singleBar.Key != 0)
                    {
                        CodeBuilder.AppendCode("PHA", "Preserve A (current multiplication result)");
                        CodeBuilder.AppendCode("CLC : ADC #$" + singleBar.Key.ToString("X4"), "Add rate.");
                    }
                    CodeBuilder.AppendCode("STA $" + (FreeRAM + i).ToASMString(), "Store to FreeRAM for indirect HDMA");
                    //also don't restore A if there is no wind.
                    if (singleBar.ElementAt(0).Autoscroll&& singleBar.Key != 0)
                    {
                        CodeBuilder.AppendCode("PLA", "Restore A (current multiplication result)");
                    }

                    //keep track of the address for normal scrolling behaviour (multiplier = 1, no auto scroll)
                    if (bar.Key == 1.0 && singleBar.ElementAt(0).Autoscroll&& singleBar.Key != 0)
                    {
                        addresseForOne = FreeRAM + i;
                    }

                    //remember which address has this specs in dictionary with hashcode
                    multiplierAddressMapping.Add(singleBar.ElementAt(0).GetHashCode(), FreeRAM + i);
                    i += 2;
                }
                CodeBuilder.CloseBlock();
            }

            //if the normal scrolling hasn't been set yet, make one.
            if (addresseForOne == 0)
            {
                CodeBuilder.OpenNewBlock();
                CodeBuilder.AppendCode("LDA $" + BaseAddress.ToASMString(), "Load BG x Position");
                CodeBuilder.AppendCode("STA $" + (FreeRAM + i).ToASMString(), "Store to FreeRAM for indirect HDMA");
                CodeBuilder.CloseBlock();
                addresseForOne = FreeRAM + i;
                i += 2;
            }

            //build the table
            foreach (var bar in Bars)
            {
                //fetch indirect HDMA address
                int adr = multiplierAddressMapping[bar.GetHashCode()] & 0xFFFF;
                //split it
                byte low  = (byte)(adr & 0xFF);
                byte high = (byte)((adr >> 8) & 0xFF);

                //make as many 1 scanline high entries as needed.
                var entry = new HDMATableEntry(TableValueType.dw, 1, low, high);
                _table.AddRange(Enumerable.Repeat <HDMATableEntry>(entry, bar.Scanline));
            }

            //if there aren't enough entries for the whole screen yet, fill it up with scrollrate 1.
            if (_table.Count < Original.Height)
            {
                //fetch indirect HDMA address for normal scrolling
                int adr = addresseForOne & 0xFFFF;
                //split it
                byte low  = (byte)(adr & 0xFF);
                byte high = (byte)((adr >> 8) & 0xFF);

                var entry = new HDMATableEntry(TableValueType.dw, 1, low, high);
                _table.AddRange(Enumerable.Repeat <HDMATableEntry>(entry, Original.Height - _table.Count));
            }

            //cut down table
            for (int l = _table.Count - 1; l >= Original.Height; l--)
            {
                _table.RemoveAt(l);
            }

            //add end.
            _table.Add(HDMATableEntry.End);

            CodeBuilder.AppendCode("SEP #$20", "Back to 8bit");
            CodeBuilder.AppendCode("RTL", "Return");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendTable(_table);
            CodeBuilder.CloseBlock();

            return(CodeBuilder.ToString());           // +"\n\n" + tableString;
        }