User Tools

Site Tools


asm_stylesheet

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
asm_stylesheet [2015/10/25 13:00] – [Folding Blocks Of Code] black_falconasm_stylesheet [2016/09/04 15:07] (current) – removed black_falcon
Line 1: Line 1:
- 
-====== Super Metroid Assembly Style Guide ====== 
- 
-**A guide that helps you correctly writing and organizing your ASM code to optimize your workflow and keep you motivated! :) 
-Please note that this is __NO ASM TUTORIAL!__. \\ 
-You have to know how ASM code works and how it is stored in the game's ROM in order to make use of this guide. 
-Also don't take the example code I used too seriously, it's just for educational purposes, so it doesn't matter if it makes sense or not.** 
- 
- 
-====== TABLE OF CONTENTS ====== 
- 
- 
- Introduction 
-  
- 1. Getting the right setup **done** 
- - Recommended Tools 
- - Setting up N++ 
-  
- 2. Basic code stucturization **done** 
- - One event per line 
- - Branches 
- - Folding Blocks Of Code 
- - Commentary 
-  
- 3. xkas command structurization **in progress** 
-  
- 4. Tips for Optimizing Your Workflow using N++ Macros **pending** 
- - When Disassembling 
- - When Copying a string of bytes from the ROM 
-  
- 
-====== INTRODUCTION ====== 
- 
- 
- 
-ASM coding became incredibly popular over the last years.  
-I can very well remember the old vanilla hacks that were amazing long ago at the time when asm wasn't really a thing. 
-Nowadays the amount of patches and asm resources has grown considerably, and every hack contains at least some hex tweaks or a new HUD. 
-Naturally, the more ideas are presented in a hack, the more people want to come up with new ideas and code their own thing. 
-The way these people write their code may be very different from each other, resulting sometimes in inefficient or just cluttered looking 
-code that is not really viewer-friendly. 
- 
-The goal of this guide is to give ASM coders an idea about how I think organized code should look like and how it helps you optimize it. 
-Especially if you're going to release the source later, so other coders have to understand what's going on from a different perspective, which is not an easy task. 
-Now you should know that this is by far no "official way to write ASM code", you are free to do whatever you think is best.\\ 
-I too am open for suggestions and improvements.\\ 
-In this guide I will as well cover and if necessary expand ways to improve your workflow in regards to Super Metroid ASM coding, 
-including what tools I'm using and how I disassemble large portions of code in a matter of minutes, xkas friendly using the tools listed below. 
- 
-Anyway this introduction has been a bit long so //let's get started!// 
- 
----- 
- 
-====== 1. Getting The Right Setup ====== 
- 
-===== Recommended Tools ===== 
- 
-__Essential stuff any ASM coder should have before even reading this guide:__ 
- 
-  * [[super_metroid:editor_utility_guides:smile2.5|SMILE]] - well you might be thinking "duh..", the feature essential here is the file comparison\\ 
-  * [[http://www.smwcentral.net/?p=section&a=details&id=4615|xkas]] - does not just apply asm code, it has a ton of super useful features hardly anyone knows about\\ 
-  * [[http://www.zophar.net/snes/geiger-s-snes9x-debugger.html|Geigers SNES9x Debugger]] - I'm using 1.51, which is quite glitchy graphics-wise, but it works very well to disassemble code\\ 
-  * [[ http://fusoya.eludevisibility.org/la/ | Lunar address]] - If you don't know this program then you're not a hacker. What is bank and what is pointer? GO LEARN!\\ 
-  * Hex Editor - [[http://mh-nexus.de/de/downloads.php?product=HxD|HxD]] recommended, also has file comparison if you prefer this one\\ 
-  * calculator - anything that can calculate and convert between 0x <> 0d <> 0b (you better know what those mean)\\ 
- 
-__Tools recommended that once used you don't want to miss anymore:__ 
- 
-   * [[https://notepad-plus-plus.org/ |Notepad++]] and [[https://dl.dropboxusercontent.com/u/18141148/website/Hacking%20Stuffz/65816asm%28xkasv06%29.xml |my ASM Stylesheet]]           - A synonym for "saving years of your life", in this guide we'll be using my custom ASM stylesheet 
-   * [[http://www.romhacking.net/utilities/395/ |SNES Professional ASM Development kit]] - Allows you to view and modify asm code directly in the ROM. 
- 
- 
-__Even more essential stuff and the reason I get out of bed every morning:__ 
- 
-   * Coffee                                 - needed in order for programmers to convert it into code 
- 
-__Other things:__ 
- 
-   * a brain                                - well, not quite as essential maybe, some people don't have one, so you don't necessarily need it 
- 
----- 
-===== Setting up Notepad++ ===== 
- 
-N++ is one of, if not the most versatile and popular code viewers out there. It supports lots of different programming languages such as batch or C++. 
-If the language you need is not supported, you can simply define it nice and easy using the custom language feature. 
-Lucky for you I already made one for SNES ASM so you don't have to bother. 
-To add the ASM language stylesheet, open up N++ and go to Language > User-defined (at the very bottom) 
-Alternatively you can simply click the toolbar icon for it (it's a window with a lightning drawn into it) 
- 
-{{:asmguidecustomlang1.png|}} 
- 
-In the opened window, click 'import' and select my stylesheet: 
- 
-{{:asmguidecustomlang2.png|}} 
- 
-Now the default theme has a white background, which is a pain in the eyes (that's why I use an all black background) 
-To change that, click ''Settings >> Style Configurator'', and under ''Select Themes'', select a dark theme you like (I'm using black board) 
-If you're still not happy with the slight blueish background or whatever color your theme's bg has,  
-under ''Global Styles >> Default Style >> background color'' you can change it to black. 
-Try to mess with it a bit, and when you're comfortable, let's continue with Part 2 of this guide! 
- 
----- 
-====== 2. Basic code structure ====== 
- 
-===== One Event Per Line ===== 
- 
-The following example shows how I used to write code when I just got started: 
- 
- LDA #$E17D ;check if elevator bit is set 
- STA $099C ;code to run 
- LDA #DOOROUT ;label 
- STA $07B5 ;doorout!!! 
- LDA !value ;would be value 1 
- ASL a ; 2 ;doorout pointer will be my custom code (!doorout) 2 + DOOROUT 
- ADC $07B5 
- TAX  
- LDA $8F0000,x ;loads Door Definition code pointer 
- STA $078D ;stores the pointer here 
- LDA #$7777 
- STA !flag2 
- LDA !Istay 
- STA !nextinst 
- LDA #$000A ;09 = execute $099C 
- ;STA $0998 ;also initiate room transition 
- RTS 
- 
-... and this is a good example of how **not** to write your code. You can see it takes up lots of lines and overall is not very nice to look at. 
-So instead of using one opcode + argument per line, try to use **one event/statement per line**.\\ 
- 
-Now what's a statement?\\ 
----- 
-//**A statement is a combination of opcodes and arguments, which creates either a check, performs an operation or causes any kind of change to a value and things such as RAM adresses and hardware registers.**// 
----- 
- 
-Most statements consist of three steps: reading >> calculating/masking >> writing/checking 
- 
-an example statement would be an addition operation: 
- 
- LDA $09C2 ;reading 
- CLC 
- ADC #$0001 ;calculating 
- STA $09C2 ;writing (simple, nuh?) 
- 
-Now this can be organized to have the operation on a single line: 
- 
- LDA $09C2 : CLC : ADC #$0001 : STA $09C2 
-  
-"What, you could do that?!" Sure thing you can! 
- 
-Unorganized check statement(also referred to as conditional branching): 
- 
- LDA $09C2 ;reading 
- AND #$FF00 ;masking 
- CMP #$0E00 ;\checking (I think you get the idea) 
- BEQ Branch ;/ 
- 
-Organized check: 
- 
- LDA $09C2 : AND #$FF00 : CMP #$0E00 : BEQ Branch 
- 
-Now what if there's a combination of the two like the one below? 
- 
- LDA $09C2 
- CMP #$0E00 
- BEQ Branch 
- LDA $09C2  
- CLC 
- ADC #$0001 
- STA $09C2 
- Branch: 
- LDA #$0E00 
- STA $09C2 
- 
-Easy, just remember one statement per line: 
- 
- LDA $09C2 : CMP #$0E00 : BEQ Branch 
- LDA $09C2 : CLC : ADC #$0001 : STA $09C2 
- Branch: LDA #$0E00 : STA $09C2 
- 
-Notice that the branch labels can be put into the same line right before the code without looking cluttered. 
-Please **avoid** trying to merge multiple statements all into one line like this: 
- 
-         LDA $09C2 : CMP #$0E00 : BEQ Branch : LDA $09C2 : CLC : ADC #$0001 : STA $09C2 
- Branch: LDA #$0E00 : STA $09C2 
- 
-Other examples of statements/events: 
- 
-   * Loading an immediate value followed by a jump to a subroutine that uses it (and optionally gives output based on it): 
- 
- LDA #$0001 : JSL $8081DC : BCS Branch 
- 
-   * Loops: 
- 
- LDX #$000A 
- back: LDA $12 : CLC : ADC $07A5 : STA $12 
- DEX : CPX #$0000 : BPL back 
-  
-Three statements make up this loop: Initializing X, calculating/changing an address value, and increasing/checking X), thus I used three lines. 
-Now there are some special cases of statements, especially when it comes to checking several bits in a respective order like button inputs or items: 
- 
- LDA $09A2 
- BIT #$0020 
- BNE GRAV 
- BIT #$0001 
- BNE VAR 
- BRA OUT 
- 
-For this there are multiple ways, one is using tabs/spaces for alignment: 
- 
- LDA $09A2 : BIT #$0020 : BNE GRAV 
- BIT #$0001 : BNE VAV 
- BRA OUT 
-  
-Another way would be to simply give LDA $09A2 its own line: 
- 
- LDA $09A2 
- BIT #$0020 : BNE GRAV 
- BIT #$0001 : BNE VAV 
- BRA OUT 
- 
-Simple return statements (''RTS'', ''RTL'') should have their own line, except if used with carry operations: 
- 
- CLC : RTS 
- SEC : RTL 
-  
-Any kind of status register statements as well as conditionless jumps (''BRA'', ''JMP'', ''JML'') should each be on a single line: 
- 
- SEP #$30 
- LDX #$0A : LDA #$04 : STA $0000,x 
- REP #$30 
- BRA OUT 
-  
-**Stack operations** should be put together onto a **single line**, for easy recognition of the order they are in  
-(wrong order of pushing onto/pulling from stack is the main reason for emulator crashes!): 
- 
- PHX : PHY : PHP 
- REP #$30 
- [code] 
- PLP : PLY : PLX ;always have to be pulled in the reversed order in what they were pushed 
- RTL 
-  
-Block movement organization: 
- 
- PHB 
- LDA #$00FF : LDX #$8000 : LDY #$1000 : MVN $897E 
- PLB 
- RTS 
- 
-----  
-===== Branches===== 
- 
-There are three ways to define a branch in xkas that in the end do the same thing.\\ 
-The first one requires you to know how many bytes an opcode's argument takes up (if it is using any) plus one (the opcode itself), also paying attention to 16/8bit mode: 
- 
- REP #$20 
- LDA $09A2 : AND #$0001 : BNE $02 
- BRA $06 
- LDA #$0020 : TRB $09A2 
- RTS 
-  
-But as you can see, this is quite awkward and would not really make sense, since xkas does calculate the pc offset for you using labels.\\ 
-Also actually seeing the branch destination is always better, right? 
-So the second way would be to simply be using **labels to name the branches**: 
- 
- REP #$20 
- LDA $09A2 : AND #$0001 : BNE VAR 
- BRA OUT 
- VAR: STZ $09A2 
- OUT: RTS 
-  
-Alright, up to this point, that should be common knowledge, even for ASM beginners. 
-Now if you have a ton of code and are tired of naming all your branches, there's a solution!\\ 
-Xkas has a nifty feature that lets you use sublabels (+/- signs) for branches, depending on whether the branching direction is positive or negative. 
- 
- "Sublabels allow you to reuse redundantly named labels such as loop, end, etc. without causing duplicate label conflicts. 
- A new sublabel group is started immediately after a label is declared automatically. 
- A +/- label can be up to 3 levels deep, e.g. +, ++, +++, -, --, ---. 
- They overwrite their pc offsets immediately after being redefined. 
- Useful for very short loops, when even something like .loop would become redundant in a long routine." 
- 
-This is a quote from the xkas help file. 
-(which you should have read! Seriously if you didn't, just take a look, it's the .html file that's included in the xkas zip file!)\\ 
-Now what does that mean exactly? 
- 
- LDA $12 : CMP #$000A : BEQ Go 
- LDX #$0009  
- Back: LDA $12 : CLC : ADC #$0001 : STA $12 
- DEX : CPX #$0000 : BPL back 
- Go: RTS 
- 
-Let's assume you're using the above kind of loop several times.\\ 
-It still would require you to think of appropriate and unique label names all the time so you don't get things confused. 
-That wouldn't be the only issue, though. \\ 
-You'd have to write the same label for each branch if your routine checks for a lot of things and branches to "GetOut:" like 20 times. 
- 
- 
- 
-This is the loop example, but this time using sublabels: 
- 
- LDA $12 : CMP #$000A : BPL + 
- LDX #$000A  
- - LDA $12 : CLC : ADC #$0001 : STA $12 
- DEX : CPX #$0000 : BPL - 
- + RTS 
- 
-Okay, now I'm perfectly aware that using them in a single loop is kinda lame and doesn't convince you, but what would you say if you can use + and - over and over again? 
-Like this: 
- 
- LDA $09C2 : CMP #$0010 : BPL + ;this branch... 
- LDX #$0010  
- - LDA $09C2 : CLC : ADC #$0002 : STA $09C2 
- DEX : CPX #$0000 : BPL - 
- + LDA $09C6 : CMP #$000A : BEQ + ;...goes to here 
- LDX #$000A 
- - LDA $09C6 : CLC : ADC #$0002 : STA $09C6 
- DEX : CPX #$0000 : BPL - 
- + LDA $09CA : CMP #$1FFF : BEQ +  
- LDX #$1FFF 
- - LDA $09CA : CLC : ADC #$0005 : STA $09CA ;whereas here is where... 
- DEX : CPX #$0000 : BPL - ;...this branch goes to 
- + RTS 
- 
-Awesome, isn't it? 
-Okay this criss-crossing might look confusing at first, but try to understand where each of the branches go to.\\ 
-Now what does "up to 3 levels deep" mean? 
-It means that there can be multiple branch levels, so you have to use just as much levels for the sublables: 
- 
- REP #$20 
- LDA $09A2 : AND #$0001 : BNE + ;branch 1, level 1 
- BRA ++ ;branch 2 (located *before* destination 1 , thus level 2) 
- + STZ $09A2 ;destination 1 
- ++ RTS ;destination 2 
- 
-Note that branch 2 comes **before** the destination 1 meaning in order to actually assign branch 2 to destination 2, you have to use ++ (level 2) 
-This is regardless of whether destination 2 is located before or after destination 1! 
- 
-The same counts for - signs, and for going back in the pc count: 
- 
- LDY #$000A 
- -- LDX #$0005 ;destination 2 
- - LDA 1000,x : CLC : ADC $8000,y : STA $1000,x ;destination 1 
- DEX : DEX : CPX #$0000 : BPL - ;branch 1 
- DEY : DEY : CPY #$0000 ; BPL -- ;branch 2 
-  
-Please note that you can't mix the use of labels and sublabels, like this: 
- 
- LDY #$000A 
- - LDX #$0005 ;destination 2 
- back: LDA 1000,x : CLC : ADC $8000,y : STA $1000,x ;destination 1 
- DEX : DEX : CPX #$0000 : BPL back ;branch 1 
- DEY : DEY : CPY #$0000 ; BPL - ;branch 2 
- 
-xkas will give out an error, saying negative branch too long, as it isn't able to calculate the location for - due to interference with a normal label. (At least as of version v.06, dunno if this has been fixed already) 
- 
----- 
-===== Folding Blocks Of Code ===== 
-  
-You can use the brackets/braces ''{ }'' to collapse code by clicking the [-] box on the left. 
-Xkas will ignore them, so you're free to use them anywhere. 
- 
-__Example:__ 
- 
- JSR $A4D6 
- { ;this line will be the only one left visible if collapsed 
- ASL A : TAX 
- LDY $A4EB, X : BNE BRANCH 
- SEC : RTS 
- BRANCH: LDX #$00E2 : LDA #$000E : JSL $A9D2E4 
- CLC : RTS 
- } 
- 
-In N++, it'll look like this: 
- 
-{{:collapse1.png|}} 
- 
-Collapsed: 
- 
-{{:collapse2.png|}} 
- 
-  
-Not really much to say, except you should have as many open brackets as closed ones, else N++ won't collapse them correctly. 
-By default, if you open a asm file in N++, everything is unfold. 
-To fold/collapse all the text blocks, goto ''View > Fold All'' 
- 
- 
-===== Commentary ===== 
- 
- 
-Commentary is very important for getting and keeping a better understanding of what's going on. 
-But it's easy to cross the line and soak your code with unnecessarily detailed comments about things. \\ 
-It helps just about as much as having bareboned code without any extra word, no one's gonna read anything. 
-However since I showed you the concept of one event/statement per line, it'll actually prevent you from doing so. 
- 
-This code has too much info, which is only useful for absolute ASM beginners: 
- 
- LDA $09A2 ;Load item address 
- AND #$0001 ;mask varia bit 
- CMP #$0001 ;check if it is set 
- BEQ VAR ;branch if varia is equipped 
- 
-Using the one-statement-per-line rule: 
- 
- LDA $09A2 : AND #$0001 : CMP #$0001 : BEQ VAR ;check if varia is equipped 
-  
-You notice that it doesn't need that much info, a simple comment about the event/statement itself is totally sufficient, but still better than none.\\ 
-If you don't know how specific opcodes work exactly, feel free to ask, that's what Metconst is for after all!\\ 
-Now again you don't HAVE to use comments, only if you feel things need a short explaination. 
- 
- 
- 
-====== 3. xkas command structurization (WIP) ====== 
- 
- 
-In the ASM stylesheet, all the xkas commands are blue by default. 
-Most commonly used commands are ''DB'' (Data Byte), ''DW'' (Data Word), ''DL'' (Data Long) and ''org'' (sets file position) 
-''org'' along with an optional label should always be put onto a single line, and if necessary be on the same line after the open brace to collapse the code that is following afterwards. 
- 
-__Example:__ 
- 
- { org $808000 ;again, this line will stay visible even when collapsed, use this as a "bookmark" to easily find certain chunks of code. 
- DW $0000 : DW $0001 : DL $7E8000 : DB $FF  
- } 
- 
-__Example using labels:__ 
- 
- { org $BF8000 : TABLE: ;note the colon between org and label 
-  
- DW $0001 : DW $0002 : DW $0004 : DW $0008 
- DW $0010 : DW $0020 : DW $0040 : DW $0080 
- DW $0100 : DW $0200 : DW $0400 : DW $0800 
- DW $1000 : DW $2000 : DW $4000 : DW $8000 
- } 
- 
-__Xkas fill functions organzation:__ 
- 
- org $808000 : padbyte $FF : pad $808010 ;should always be on one line 
- fillbyte $ff : fill 16 
- 
-__Repeatedly used opcodes:__ 
- 
-Instead of writing a bunch NOPs and ASLs all over the place like this: 
- 
- NOP : NOP : NOP 
- NOP : NOP  
- NOP 
- NOP 
- LDA $07A5 : AND #$00FF : ASL : ASL : ASL : ASL : STA $0AF6 
- 
-...you can let xkas create pseudo upcodes using # and a number (always decimal): 
- 
- NOP #7 ;this equals NOP : NOP : NOP : NOP : NOP : NOP : NOP 
- LDA $07A5 : AND #$00FF : ASL #4 : STA $0AF6 
- 
-But be careful when writing to status register (''SEP'',''REP'') or 8 bit operations to not forget the '$' sign: 
- 
- SEP #$20 
- LDA #$10 : STA $7ECD20 
- REP #20 ;forgetting '$' will instead write REP #$00 20 times, meaning a total 40 bytes are written! 
- 
- 
- 
- 
- 
- 
- 
-====== 4. Tips for Optimizing Your Workflow using N++ Macros (Pending) ====== 
- 
-More to come soon! 
- 
- 
- 
- 
- 
  
asm_stylesheet.1445778053.txt.gz · Last modified: 2015/10/25 13:00 by black_falcon