diff --git a/SourceGen/Examples/Scripts/Sample.dis65 b/SourceGen/Examples/Scripts/FinishedSample.dis65 similarity index 100% rename from SourceGen/Examples/Scripts/Sample.dis65 rename to SourceGen/Examples/Scripts/FinishedSample.dis65 diff --git a/SourceGen/Examples/Tutorial/Tutorial2 b/SourceGen/Examples/Tutorial/Tutorial2 index 222f439..d550ec9 100644 Binary files a/SourceGen/Examples/Tutorial/Tutorial2 and b/SourceGen/Examples/Tutorial/Tutorial2 differ diff --git a/SourceGen/Examples/Tutorial/Tutorial2.S b/SourceGen/Examples/Tutorial/Tutorial2.S index dae5c7a..147e81f 100644 --- a/SourceGen/Examples/Tutorial/Tutorial2.S +++ b/SourceGen/Examples/Tutorial/Tutorial2.S @@ -53,7 +53,10 @@ stringtab dw string3 copydone - lda #$ff + jsr PrintInlineZString + asc 'Embedded!',00 + + lda #$ff ;self-modifying code example sta _mod+1 _mod lda #$00 bne skipbrk @@ -62,12 +65,12 @@ middat ds 4 outdat ds 1 skipbrk - lda middat + lda middat ;nearby-label example ora middat+1 and middat+2 eor middat+3 - ldx #$00 + ldx #$00 ;embedded instruction example dfb $2c rebr ldx #$01 sta outdat @@ -85,3 +88,27 @@ thing lda INPUT rts +PrintInlineZString + pla + sta PTR1 + pla + sta PTR1+1 + ldy #$01 +:loop lda (PTR1),Y + beq strend + ora #$80 + jsr $FDED + iny + bne :loop + +strend tya + clc + adc PTR1 + sta PTR1 + lda PTR1+1 + adc #$00 + pha + lda PTR1 + pha + rts + diff --git a/SourceGen/RuntimeData/Help/tutorials.html b/SourceGen/RuntimeData/Help/tutorials.html index f6a8aef..cea1311 100644 --- a/SourceGen/RuntimeData/Help/tutorials.html +++ b/SourceGen/RuntimeData/Help/tutorials.html @@ -22,6 +22,7 @@ manual is recommended.
LDA #<XDATA
and LDA #>XDATA
.
Let's give the pointer a name. Select line $203d, and use Actions > Create Local Variable Table to create an empty table. -Click "New Symbol" on the right side. Set the Label field to "PTR1", -the Value field to $02, and the width to 2 (it's a 2-byte pointer). Leave -the Address button selected. Click "OK" to create the entry, and then +Click "New Symbol" on the right side. Leave the Address button selected. +Set the Label field to "PTR1", the Value field to $02, and the width +to 2 (it's a 2-byte pointer). Click "OK" to create the entry, and then "OK" to update the table.
There's now a ".var" statement (similar to a .equ) above line $203d, and the stores to $02/$03 have changed to "PTR1" and "PTR1+1".
@@ -460,18 +461,42 @@ means the zero-flag is clear.) you add an end-of-line comment, it appears after the cycle count.Hit Ctrl+S to save your project. Make that a habit.
+Consider the code at address $206B. It's a JSR followed by some +ASCII text, then a $00 byte, and then what might be code. Double-click +on the JSR opcode to jump to $20AB to see the function. It pulls the +call address off the stack, and uses it as a pointer. When it encounters +a zero byte, it breaks out of the loop, pushes the adjusted pointer +value back onto the stack, and returns.
+This is an example of "inline data", where a function uses the return +address to get a pointer to data. The return address is adjusted to +point past the inline data before returning (technically, it points at +the very last byte of the inline data, because RTS jumps to address + 1).
+To format the data, we first need to tell SourceGen that there's data +in line with the code. Select the line at address $206E, then +shift-click the line at address $2077. Use Actions > Hint as Inline Data.
+The data turns to single-byte values, and we now see the code +continuing at address $2078. We can format the data as string by +using Actions > Edit Operand, setting the Character Encoding to "Low or +High ASCII", and choosing "null-terminated strings".
+ +That's pretty straightforward, but this could quickly become tedious if +there were a lot of these. SourceGen allows you to define scripts to +automate common formatting tasks. This is covered in a later tutorial.
+The rest of the code isn't really intended to do anything useful. It just exists to illustrate some odd situations.
-Look at the code starting at $206b. It ends with a BRK at $2074, which +
Look at the code starting at $2078. It ends with a BRK at $2081, which as noted earlier is a bad sign. If you look two lines above the BRK, you'll see that it's loading the accumulator with zero, then doing a BNE, which should never be taken (note the cycle count for the BNE is 2). The trick is in the two lines before that, which use self-modifying code to change the LDA immediate operand from $00 to $ff. The BNE is actually a branch-always.
-We can fix this by correcting the status flags. Select line $2072, +
We can fix this by correcting the status flags. Select line $207F, and then Actions > Override Status Flags. This lets us specify what the flags should be before the instruction is executed. For each flag, we can override the default behavior and specify that the flag is @@ -481,13 +506,13 @@ in the "Z" column click on the button in the "Zero" row. Click "OK". The BNE is now an always-taken branch, and the code list rearranges itself appropriately (and the cycle count is now 3).
-Continuing on, the code at $2079 touches a few consecutive locations. Edit -the label on line $2074, setting it to "STUFF". Notice how the references -to $2074 through $2077 have changed from auto-generated labels to +
Continuing on, the code at $2086 touches a few consecutive locations. Edit +the label on line $2081, setting it to "STUFF". Notice how the references +to $2081 through $2084 have changed from auto-generated labels to references to STUFF. For some projects this may be undesirable. Use Edit > Project Properties, then in the Analysis Parameters box un-check "Seek nearby targets", and click "OK". You'll notice that the -references to $2075 and later have switched back to auto labels. If +references to $2081 and later have switched back to auto labels. If you scroll up, you'll see that the references to PTR1+1 and PTR2+1 were not affected, because local variables use explicit widths rather than the "nearby" logic.
@@ -495,7 +520,7 @@ than the "nearby" logic. avoid explicitly labeling every part of a multi-byte data item. For now, use Edit > Undo to switch it back on. -The code at $2085 looks a bit strange. LDX
, then a
+
The code at $2092 looks a bit strange. LDX
, then a
BIT
with a weird symbol, then another LDX
. If
you look at the "bytes" column, you'll notice that the three-byte
BIT
instruction has only one byte on its line. The
@@ -503,7 +528,7 @@ trick here is that the LDX #$01
is embedded inside the
BIT
instruction. When the code runs through here, X is set
to $00, then the BIT
instruction sets some flags, then the
STA
runs. Several lines down there's a BNE
-to $2088, which is in the middle of the BIT
instruction.
+to $2095, which is in the middle of the BIT
instruction.
It loads X with $01, then also continues to the STA
.
Embedded instructions are unusual but not unheard-of. (This trick is used extensively in Microsoft BASICs, such as Applesoft.) When you see the @@ -513,9 +538,7 @@ on.
This tutorial covers one specific feature.
- -This tutorial covers one specific feature.
Start a new project. Select the Apple //e platform, click Select File and navigate to the Examples directory. In A2-Amper-fdraw, select @@ -588,6 +611,59 @@ code entry point hint -- but did several of them at once.
SourceGen asks for confirmation, click Discard & Continue. +This tutorial covers one specific feature.
+ +Some repetitive formatting tasks can be handled with automatic scripts. +This is especially useful for inline data, which confuses the disassembler +because code is expected.
+An earlier tutorial demonstrated how to manually mark bytes as +inline data. We're going to do it a faster way. For this tutorial, +start a new project with "Generic 6502", and in the SourceGen +installation directory find the Examples directory, open the Scripts +subdirectory, and select "Sample".
+We'll need to load scripts from the project directory, so we have to +save the project. File > Save, call it the default name (Sample.dis65).
+ +Take a look at the disassembly listing. The file starts with a JSR +followed by a string that begins with a small number. This appears to be +a string with a leading length byte. We want to load a script that +can handle that, so use Edit > Project Properties, select the +Extension Scripts tab, click "Add Scripts from Project", and then +the file "InlineL1String.cs". Click OK.
+Nothing happened. If you look at the script (and you know some C#), +you'll see that it's looking for a JSR to a function called +"PrintInlineL1String". So let's give it one.
+Double-click the JSR operand ("L1026"), click "Create Label", and +enter "PrintInlineL1String". Remember that labels are case-sensitive; +you must enter it exactly as shown. Hit OK to accept the label, and OK +to close the operand editor. If all went well, address $1003 should now be +an L1 string "How long?", and adress $100D should be another JSR.
+ +The next JSR appears to be followed by a null-terminated string, so +we'll need something that handles that. Go back into Project Properties +and add the script "InlineNullTermString.cs".
+This script is slightly different, in that it handles any JSR to a label +that starts with "PrintInlineNullString". So let's give it a couple of +those.
+Double-click the operand on line $100D ("L1027"), click Create Label, +and set the label to "PrintInlineNullStringOne". Hit OK twice. That +formatted the first one and got us to the next JSR. Repeat the process +on line $1019 ("L1028"), setting the label to "PrintInlineNullStringTwo".
+ +The entire project is now nicely formatted. In a real project the +"Print Inline" locations would be actual print functions, not just RTS +instructions, and there would be multiple JSRs to a single function. +So labeling a single print function could format dozens of inline strings +and clean up the disassembly automatically.
+ +Extension scripts can make your life much easier, but they do require +some programming experience. See the +manual for more details.
+ + +That's it for the tutorials. Significantly more detail on