Translating to ASM For many people - especially those without significant programming experience - it can be hard to transform "this is what I want the code to do" into "this is what it should actually look like". Right now we're going to practice translating basic ideas into assembly language so that you can see how the instructions fit together to create more complex actions. Let's step away from the world of Cave Story for a while. Pretend that you're a computer programmer who is trying to design a music player[1]. This is what part of it might look like: if the music player is ready then play song 1 otherwise wait for user to press a buttonAn if ... then statement is a very common expression used in computer programming to control how programs operate.In assembly, the idea is exactly the same. Instead of if ... then we have CMP ... (jump) , where (jump) refers to any jump instruction that checks for a condition, such as JE, JNE, JGE, JG, and so on.If (this is true), then (do something) if variable X is 0 then add 3 to variable X afterwards do nothingThe 3 statements above are written in "psuedocode", which means fake code. It's not real code yet, but it's useful enough so that we have a guiding system before we decide to write some assembly. That said, let's translate psuedocode to ASM. Here I will choose EAX to replace "variable X" in the psuedocode. Address Instruction 00494201 CMP EAX,0 ;Is EAX equal to 0 or not? 00494204 JNE 494209 ;If no, don't add 3 to EAX. 00494206 ADD EAX,3 ;If yes, then add 3 to EAX. 00494209 NOP ;Do nothing.Notice that the "then statement" is only executed if the "if statement" is true. If the "if statement" is not true, then the "then statement" is ignored. The "afterwards" statement is executed regardless of whether the last "if statement" is true or not. What if you want two things to be true at the same time? if (variable X is 0 and variable Y equals variable Z) then store 1 to variable X store 0 to variable Y otherwise store 2 to variable X calculate Z minus Y store answer to Z afterwards push X, Y, and Z onto the stack.Now that piece of psuedocode is much more complicated. We can still translate it though. I will choose EAX to replace variable X, ECX to replace variable Y, and EDX to replace variable Z. Address Instruction 00493801 CMP EAX,0 ;Is EAX equal to 0? 00493804 JNE 493816 ;If not, go to PART 2. 00493806 CMP ECX,EDX ;Is ECX equal to EDX? 00493808 JNE 493816 ;If not, go to PART 2. 0049380A MOV EAX,1 ;PART 1. Store 1 to EAX. 0049380F MOV ECX,0 ;Store 0 to ECX. 00493814 JMP 49381D ;Go to PART 3. 00493816 MOV EAX,2 ;PART 2. Store 2 to EAX. 0049381B SUB EDX,ECX ;Calculate EDX - ECX, store result to EDX. 0049381D PUSH EAX ;PART 3. Push EAX. 0049381E PUSH ECX ;Push ECX. 0049381F PUSH EDX ;Push EDX.Can we do something that's not pure math? store 0 to variable X. if Quote's current-health is less than or equal to 5 then if Quote's max-health is less than 8 then store 8 to max-health afterwards store 8 to current-health otherwise store 1 to variable X. afterwards do nothingOne of the if ... then statements is nested inside another one! This is common practice in other programming languages, and assembly is no exception.Here you really need the Assembly Compendium. Look up CurrentHealth in the compendium and you'll find 49E6CC. Look up MaxHealth and you'll find 49E6D0. Address Instruction 00493915 MOV EAX,0 ;store 0 to EAX. 0049391A CMP WORD [49E6CC],5 ;Is Quote's current health less than or equal to 5? 00493922 JG 493942 ;If not, go to address 493942. 00493924 CMP DWORD [49E6D0],8 ;Is Quote's max health less than 8? 0049392B JGE 493937 ;If not, go to address 493937. 0049392D MOV DWORD [49E6D0],8 ;Make Quote's max health equal to 8. 00493937 MOV WORD [49E6CC],8 ;Heal Quote to 8 health points. 00493940 JMP 493947 ;Skip over MOV EAX,1 00493942 MOV EAX,1 ;store 1 to EAX. 00493947 NOP ;do nothing.The above piece of code will heal Quote ONLY IF Quote's current health is below or equal to 5. If Quote does get healed, then his max health will be checked. If the max health is less than 8, it will be set to 8. Then full healing occurs after that. If Quote's max health is greater than or equal to 8, he will only be healed to 8 health points (no more than that). Finally, EAX will hold the number 1 if Quote did not get healed. EAX will hold 0 if he did get healed. Also, you should notice that the player's current-health is written as WORD [49E6CC] instead of DWORD [49E6CC]. This means that the current-health can only hold 4 hexadecimal digits at maximum, but the max-health can hold 8 hexadecimal digits at maximum. Remember that a word is 16-bits (4 hex digits) and a dword is 32-bits (8 hex digits). Why is the max-health a bigger data size than the current-health? If the max-health happens to be bigger than 4 hex digits, the current-health can't reach the same value as the max-health anyway, so what's the point? I have absolutely no idea. Maybe Pixel had a good reason for doing this. Maybe he didn't. Maybe he forgot that the current-health had a size of 2 bytes and the max-health had a size of 4 bytes. Maybe he didn't bother to change it. I really don't know. Backwards Translation In order to make pre-existing ASM code more understandable to human beings, we can do backwards translation (converting ASM to ideas) in order to make better sense of assembly language. Remember that looping code from a couple of lessons ago? Well here it is: Address Instruction Comments 004937F7 MOV EAX,0 ;Store 0 to EAX. 004937FC INC EAX ;Increase EAX by 1. 004937FD CMP EAX,50 ;Compare EAX with 50 (hex). 00493800 JGE 00450DE9 ;If EAX is greater than or equal to 50 (hex), jump to 450DE9. 00493806 PUSH 9955 ;If not, push 9955 onto the stack. 0049380B JMP SHORT 004937FC ;Jump to address 4937FCNow we take the code and transform it into a format that humans can more easily read and understand: store 0 to variable X begin cycle A increase variable X by 1 if variable X is greater than 50 (hex) then break cycle A (go to address 450DE9) otherwise push 9955 (hex) onto stack repeat cycle A*takes a breath* Whew. That was a lot of code today. Previous Lesson: Call and Return Next Lesson: Math Instructions Table of Contents [1]The example music player code given is an oversimplification. A real music player would need thousands of lines of code, or possibly more, to make it work correctly. |