/// <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; }
public override string Code(string Tablename) { int Base = 0x4330 + ((Channel - 3) * 0x10); int Register = (int)_Layers; int BaseAddress = (_Layers == LayerRegister.Layer1_Y) ? Layer1_YPosition : Layer2_YPosition; int RegMode = ((Register & 0xFF) << 8) | Mode; int LSRs = (int)((1.0 / _speed) / 2.0); int Tablesize = (Scanlines / _Breite) >= 15 ? 15 : (Scanlines / _Breite); int TableInRAM = (((Scanlines / _Breite) + 1) * 3) + 1; String Table = ";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)\n" + "." + Tablename.TrimStart('.') + "\n"; for (int i = 0; i <= Tablesize; i++) { Table += "\tdb $" + _IArr[i].ToString("X2") + "\n"; } String Code = INIT_Label + "REP #$20\t\t;\\\n" + "LDA #$" + RegMode.ToString("X4") + "\t\t; | Use Mode " + Mode.ToString("X") + " on register " + Register.ToString("X") + "\n" + "STA $" + Base.ToString("X4") + "\t\t; | 43" + Channel + "0 = Mode, 43" + Channel + "1 = Register\n" + "LDA #$" + (FreeRAM & 0xFFFF).ToString("X4") + "\t\t; | Address of HDMA table\n" + "STA $" + (Base + 2).ToString("X") + "\t\t; | 43" + Channel + "2 = Low-Byte of table, 43" + Channel + "3 = High-Byte of table\n" + "LDY.b #$" + (FreeRAM >> 16).ToString("X2") + "\t\t; | Address of HDMA table, get bank byte\n" + "STY $" + (Base + 4).ToString("X") + "\t\t; | 43" + Channel + "4 = Bank-Byte of table\n" + "SEP #$20\t\t;/\n" + "LDA #$" + (0x08 << (Channel - 3)).ToString("X2") + "\t\t;\\\n" + "TSB $0D9F\t\t;/ Enable HDMA channel " + Channel + "\n" + "RTS\n\n" + MAIN_Label + "LDX #$00\t\t;\\ Init of\n" + "LDY #$00\t\t; | X and Y. Y will be the loop counter, X the index for writing the table to the RAM\n" + "LDA $13\t\t\t; | Speed of Waves\n" + "LSR #" + LSRs.ToString() + "\t\t\t; | Slowing down A\n" + "STA $00\t\t\t;/ Save for later use\n\n" + "PHB\t\t\t;\\ Push data bank\n" + "PHK\t\t\t; | Push program bank\n" + "PLB\t\t\t;/ Pull data bank\n\n" + ".Loop\n" + "LDA #$" + _Breite.ToString("X2") + "\t\t;\\ Set scanline height\n" + "STA $" + FreeRAM.ToString("X6") + ",x\t\t; | for each wave\n" + "TYA\t\t\t; | Transfer Y to A\n" + "ADC $00\t\t\t; | Add in frame counter\n" + "AND #$" + Tablesize.ToString("X2") + "\t\t; | only the lower half of the byte\n" + "PHY\t\t\t; | Push Y, so that the loop counter isn't lost.\n" + "TAY\t\t\t;/ Transfer A to Y\n\n" + "LDA.w ." + Tablename.TrimStart('.') + ",y\t;\\ Load in wave values\n" + "LSR A\t\t\t; | half of waves only\n" + "CLC\t\t\t; | Clear carry flag for proper addition\n" + "ADC $" + BaseAddress.ToString("X4") + "\t\t; | Add value from the wave table to layer x position (low byte).\n" + "STA $" + (FreeRAM + 1).ToString("X6") + ",x\t\t; | X position low byte\n" + "LDA $" + (BaseAddress + 1).ToString("X4") + "\t\t; | Load layer x position (high byte).\n" + "ADC #$00\t\t; | Add #$00 without clearing the carry for pseude 16-bit addition\n" + "STA $" + (FreeRAM + 2).ToString("X6") + ",x\t\t;/ X position high byte\n\n" + "PLY\t\t\t;\\ Pull Y (original loop counter)\n" + "CPY #$" + (Scanlines / _Breite).ToString("X2") + "\t\t; | Compare with #$" + (Scanlines / _Breite).ToString("X2") + " scanlines\n" + "BPL .End\t\t; | If bigger, end HDMA\n" + "INX\t\t\t; | Increase X, so that in the next loop, it writes the new table data at the end of the old one...\n" + "INX\t\t\t; | Increase X, ...instead of overwriting it.\n" + "INX\t\t\t; | Increase X\n" + "INY\t\t\t; | Increase Y\n" + "BRA .Loop\t\t;/ Do the loop\n\n" + ".End\n" + "PLB\t\t\t;\\ Pull data bank. Not doing this would be ugly...\n" + "LDA #$00\t\t; | End HMDA by writing\n" + "STA $" + (FreeRAM + 3).ToString("X6") + ",x\t\t; | #$00 here\n" + "RTS\t\t\t;/ Return"; Code += "\n\n\n" + Table; return(Code); }
public String Code(List <ScrollData> Table) { if (Table == null || Table.Count == 0) { return(""); } String BaseTable = ".ScanlineTable\n"; int CountLines = 0; foreach (ScrollData SD in Table) { if (SD.LineCount <= 0x80) { BaseTable += "\tdb $" + SD.LineCount.ToString("X2") + ",$00,$00\n"; } else { BaseTable += "\tdb $80,$00,$00\n"; BaseTable += "\tdb $" + (SD.LineCount - 0x80).ToString("X2") + ",$00,$00\n"; } CountLines += SD.LineCount; if (CountLines >= Scanlines) { break; } } BaseTable += "\tdb $00\n"; Table.Sort(); var GroupedTable = Table.GroupBy(Tab => Tab.ScrollRate); int Base = 0x4330 + ((Channel - 3) * 0x10); int RegMode = (((int)LayerRegister.Layer2_X << 8) & 0xFF00) + Mode; String Code = INIT_Label + "REP #$20\t\t;\\\n" + "LDA #$" + RegMode.ToString("X4") + "\t\t; | Use Mode " + Mode.ToString("X2") + " on register " + ((int)LayerRegister.Layer2_X).ToString("X4") + "\n" + "STA $" + Base.ToString("X4") + "\t\t; | 43" + Channel + "0 = Mode, 43" + Channel + "1 = Register\n" + "LDA #$" + (FreeRAM & 0xFFFF).ToString("X4") + "\t\t; | Address of HDMA table\n" + "STA $" + (Base + 2).ToString("X") + "\t\t; | 43" + Channel + "2 = Low-Byte of table, 43" + Channel + "3 = High-Byte of table\n" + "LDY.b #$" + (FreeRAM >> 16).ToString("X2") + "\t\t; | Address of HDMA table, get bank byte\n" + "STY $" + (Base + 4).ToString("X") + "\t\t; | 43" + Channel + "4 = Bank-Byte of table\n" + "SEP #$20\t\t;/\n" + "LDA #$" + (0x08 << (Channel - 3)).ToString("X2") + "\t\t;\\\n" + "TSB $0D9F\t\t;/ Enable HDMA channel " + Channel + "\n" + "RTS\n\n" + MAIN_Label + "LDX #$" + (Table.Count * 3).ToString("X2") + "\t\t;\\ Index for the table\n" + ".Loop\t\t\t; | Loop label...\n" + "LDA .ScanlineTable,x\t; | Load the value from the table\n" + "STA $" + FreeRAM.ToString("X6") + ",x\t\t; | And store it to the FreeRAM\n" + "DEX\t\t\t; | Decrease x, so next time we load the next lower value from the table.\n" + "BPL .Loop\t\t ;/ If x is still inbetween #$00 and #$7F we loopback.\n\n" + "REP #$20\t\t;\\ It's 16bit-mode-time kids.\n"; foreach (IGrouping <double, ScrollData> temp in GroupedTable) { if (temp.Key == 0) { continue; } double Val = temp.Key; int LSRASL = (int)(Math.Log((Val < 1) ? (1.0 / Val) : Val) / Math.Log(2)); Code += "LDA $" + Layer2_XPosition.ToString("X4") + "\t\t; | Load the Layer 2 x-position\n" + ((Val < 1) ? "LSR " : "ASL ") + "#" + LSRASL + "\t\t\t; | Apmlive scrolling\n"; foreach (var item in temp) { Code += "STA $" + (FreeRAM + (1 + (3 * item.Index))).ToString("X6") + "\t\t; | Store scrollrate to table in RAM\n"; } } Code += "SEP #$20\t\t;/ Back to 8bit\n" + "RTS\n\n" + ";The Table takes up " + (Table.Count * 3 + 1) + " bytes of the free RAM\n" + ";It ranges from $" + FreeRAM.ToString("X6") + " - $" + (FreeRAM + (Table.Count * 3)).ToString("X6") + " (both addresses included)\n" + BaseTable; return(Code); }
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; }