**Part
2: Some Basic Commands**

Lesson 2-1: Loading, Storing, and Returning

Lesson 2-2: Arithmetic Commands

Lesson 2-3: Transferring

Lesson 2-4: Branching and Conditional Statements

Lesson 2-5: Jumping

*Lab 1: BTSD Blocks

Lesson 2-6: Indexing

Lesson 2-7: Bitwise Operations

__Lesson
2-1: Loading, Storing, and Returning__

__Opcodes:
LDA, LDX, LDY, STA, STX, STY, STZ, RTS, RTL__

__Addressing
modes: imm8/16, dp, abs, long__

__Progress:__

0/99

0/15

ADC AND ASL BCC BCS BEQ BIT BMI BNE BPL BRA BRK BRL BVC BVS CLC CLD CLI CLV CMP COP CPX CPY DEC DEX DEY EOR INC INX INY JML JMP JSL JSR LDA LDX LDY LSR MVN MVP NOP ORA PEA PEI PER PHA PHB PHD PHK PHP PHX PHY PLA PLB PLD PLP PLX PLY REP ROL ROR RTI RTL RTS SBC SEC SED SEI SEP STA STP STX STY STZ TAX TAY TCD TCS TDC TRB TSB TSC TSX TXA TXS TXY TYA TYX WAI WDM XBA XCE

imm8/16 dp abs long dp,x abs,x abs,y long,x (dp) [dp] (dp),y [dp],y (dp,x) sr,s (sr,s),y

p2.1.0

The first opcode we'll learn is...*drum roll*...LDA. This stands for Load Data into Accumulator. Now, there are a few different ways to load said data. This line of code:

LDA #$02

loads the hexadecimal value 02 into A. Whatever A was before this, it is now equal to 02. Note the #$, though; you can't just LDA 02. The $ sign indicates that it is a hexadecimal value we are loading, and the # sign tells us that it is a specific number, not a RAM address. If it were this instead:

LDA $02

...you would be loading the value of RAM address $02 into A. Now, LDA $02 is perfectly valid. Just remember that LDA $02 loads the value of RAM address $02 into A. So, if $02 happens to be equal to 44, then LDA $02 loads 44 into A. If $02 = 2C, then LDA $02 loads 2C into A. Using our box analogy, “LDA #$02” would be kind of like saying “I want to put a box of rice onto the cart”, and “LDA $02” would be kind of like saying “I want to put whatever item is on the second shelf onto the cart”. By the way, you can load decimal and binary values as well. LDA #$30, for example, loads 30 in hexadecimal, but LDA #30 (without the $) loads 30 in decimal. So, to load a decimal value, simply remove the $. For binary, replace the $ with %. LDA #%10010111, for example, is equivalent to LDA #$97. I never found much use for either, but some people like to use them. I suppose loading decimal values could be nice when working with multiples of 5, such as when coding blocks that give you a certain number of coins, and loading binary values could be nice when working with bitwise commands, covered in section 2-7. So, really, although the common misconception is that a $ sign indicates a RAM address, while #$ is a number, the reality is that the $ sign merely marks the operand as being hexadecimal. I wouldn't recommend trying to load RAM addresses in decimal or binary, though...”LDA 40” might work (it would be the same thing as LDA $28), but it would do nothing but cause confusion.

p2.1.1

Now,
there are a couple different addressing modes for LDA. So far, you've
seen #$xx and $xx. The “#$xx” mode, where you load a
specific number, is called *immediate* mode, shortened to
*imm8/16*. The 8 stands for 8-bit, and the 16...well, we'll
worry about that later. (Section 3-4, if you want to know.) The “$xx”
mode, the one where you load a number from an 8-bit/1-byte RAM
address, is called *direct page* mode. There are a couple
others. You can also load a value from a 16-bit, or 2-byte, RAM
address. For example, LDA $0DC2 loads the value of the current
player's item box. LDA $14AD loads the blue P-switch timer. Now,
notice the first of these two examples: $**0**DC2, not just $DC2.
In ASM, addresses and values should always be an even number of
digits. In the first part of this, we loaded $02 and #$02, not $2 or
#$2. Similarly, we load $0DC2 and not $DC2. Anyway, the addressing
mode that loads 16-bit addresses is called *absolute* mode. The
address has 4 digits, whereas in direct page addressing mode, the
address had only 2 digits. You can go even further, though; you can
even load a 24-bit address. (This would be 3 bytes or 6 digits.) You
can, for example, LDA $7F8183. ($7F8183 is unused RAM, by the way.)
This is called *long* addressing mode. The rule for even digits
applies here as well; if you happen to be loading from an address
like, say, $0530C7, then you need that 0 in front. It isn't $530C7,
it's $0530C7.

p2.1.3

Besides
LDA, which loads a value into A, there are opcodes for X and Y as
well, which are LDX and LDY. You can LDY $14AF, LDX #$84, and many of
the other things you can do with LDA...BUT you can't use LDY or LDX
for long addresses. If you try to LDY $7F8183, for example, it won't
work. There is no long addressing mode for LDY or LDX. You can get
the value of a long address *into* X or Y (see section 2-3), but
you can't load it directly.

p2.1.4

So, to summarize:

-LDA loads a value into A.

-LDA #$xx (where xx is a value) loads a specific number. (Example: LDA #$50 loads 50 into A.)

-LDA $xx loads the value of an 8-bit/2-digit/1-byte RAM address. (Example: LDA $1A loads the value of $1A into A.) This is called direct, or direct page, addressing mode.

-LDA $xxxx loads the value of a 16-bit/4-digit/2-byte RAM address. (Example: LDA $13BF loads the value of $13BF into A.) This is called absolute addressing mode.

-LDA $xxxxxx loads the value of a 24-bit/6-digit/3-byte RAM address. (Example: LDA $7FAB10 loads the value of $7FAB10 into A.) This is called long addressing mode.

-Addresses must always have an even number of digits, 2, 4, or 6. If an address starts with a 0, such as $09, $0DBF, or $0F1348, then the initial 0 must be kept there.

-LDX and LDY load values into X or Y rather than A.

-There is, however, no 24-bit addressing mode for LDX or LDY.

p2.1.5

Well,
great! You now know three opcodes (LDA, LDX, and LDY) and four
addressing modes (immediate, direct page, absolute, and long). Now
what? Once you load a value into a register, what do you do with it?
Feed it to your dog and see if the dog burps out a Shyguy? Well, not
exactly. Once you've *loaded* a command, in most cases, if you
want to actually do anything with it, you'll need to *store* it.
To do this, you use STA, STY, and STX. STA stands for “Store
Accumulator” (or something). You can, for example, STA $19
(affect the player's powerup) or STA $0DC2 (affects the item box). An
example code that uses STA would be:

LDA #$03

STA $19

See that? This code does two things. First, it loads the value “03” into A. Second, it takes the value in A and puts that into RAM address $19, which is the player powerup. If you have Super Mario World's RAM map open right now, you can figure out that this would make the player have firepower.

p2.1.6

You
can STA to *almost* anything you can LDA from, but there are a
few exceptions. For one, there is no immediate addressing mode for
STA. You can't STA #$xx. (How would that even work? You're storing A
into a value?) You also can't STA to ROM data, although you *can*
load from it. By the way, once you STA to a RAM address, A still has
the same value it had before the STA. So, in my example code (LDA
#$03 STA $19), after you put the 03 in $19, it doesn't “go
away” as far as A is concerned. A is still equal to 03. In
fact, you can do more than one STA in a row without having an LDA
before each one. You could, for example...

LDA #$03

STA $19

STA $0DC2

STA $13CC

do
that. This loads 03 into A, then it puts that value into $19, then
$0DC2, and then $13CC. That is, it gives the player firepower ($19 =
03), puts a star in the item box ($0DC2 = 03), and then gives the
player 3 coins ($13CC = 03). (I suppose I should mention that if you
don't have the RAM map open right now, I'd open it if I were you. It
will help quite a bit.) Also, in case you were wondering, yes, you
*can* store X and Y as well. You use STX and STY for that. But
beware: just like LDX and LDY, STX and STY are much more limited than
STA is. (STA has 14 different addressing modes, while STX and STY
have only 3, to put it into perspective.) You can't use STX and STY
with long addresses, for one thing. STA $7EC800 exists, for example,
but STX $7EC800 does not.

p2.1.7

At this point, you might want to know that there is another command related to storing addresses that you will find useful: STZ. STZ is for “Store Zero”, and when you STZ a RAM address, you set that address equal to 00, no matter what it was before. For instance, without STZ, if you wanted to make the player small, you would do this:

LDA #$00

STA $19

If you wanted to erase the item from the item box, you would do this:

LDA #$00

STA $0DC2

With STZ, however, you can save yourself a bit of code. You can change that first code to:

STZ $19

and you can change the second code to:

STZ $0DC2

. It does the same thing, but it's shorter. Unfortunately, you can't use STZ on long addresses either. If you want to clear $7F9C80 to 00, you can't put STZ $7F9C80; it has to be LDA #$00 STA $7F9C80. Ah, the tragedy of life.

p2.1.8

By now, you almost know enough code to actually make something with ASM. But...BUT...there's one more thing necessary to learn: returning. You can load and store to your heart's content, but it won't do much good if you don't know how to return. To return, you use RTS or RTL. RTS stands for “Return from Subroutine”, and RTL is “Return from Subroutine, Long”. The million-dollar question is, which one should you use? Well, it depends on what it is you're coding. If it's a block for the old Blocktool, use RTS to finish the code. If it's a block for Blocktool Super Deluxe (BTSD), use RTL. If it's the main code in a patch, you usually end with RTL. If it's the INIT or MAIN routine of a sprite, use RTL, and if it's pretty much anything else in a sprite, use RTS. (You'll probably be using RTS more often, unless you decide to make a whole bunch of BTSD blocks and/or patches.) Let's have an example...

LDA #$03

STA $19

RTS

This is now a complete code. Load 03 into A, then store A (which is now 03) into $19, giving the player firepower, and then end the block of code. You don't need to put anything after RTS or RTL, by the way. There is no, for example, RTS #$01 or RTL $1540; these are two opcodes that stand alone.

p2.1.9

All right! You've successfully made it through your first ASM lesson. Let's move on to the second, shall we?.

__Lesson
2-2: Arithmetic Commands__

__Opcodes:
INC, DEC, INX, INY, DEX, DEY, ADC, SBC, CLC, SEC, ASL, LSR__

__Addressing
modes: none__

__Progress:__

9/99

4/15

ADC AND ASL BCC BCS BEQ BIT BMI BNE BPL BRA BRK BRL BVC BVS CLC CLD CLI CLV CMP COP CPX CPY DEC DEX DEY EOR INC INX INY JML JMP JSL JSR LDA LDX LDY LSR MVN MVP NOP ORA PEA PEI PER PHA PHB PHD PHK PHP PHX PHY PLA PLB PLD PLP PLX PLY REP ROL ROR RTI RTL RTS SBC SEC SED SEI SEP STA STP STX STY STZ TAX TAY TCD TCS TDC TRB TSB TSC TSX TXA TXS TXY TYA TYX WAI WDM XBA XCE

imm8/16 dp abs long dp,x abs,x abs,y long,x (dp) [dp] (dp),y [dp],y (dp,x) sr,s (sr,s),y

p2.2.0

Now,
there are various ways you can affect RAM addresses without actually
storing anything to them, and similarly, you can affect the three
variables (A, X, and Y) without actually loading something into them
per se. One way to do this is to use arithmetic commands. These are
opcodes that add, subtract, multiply, and divide. The first one we'll
learn is INC. This is short for “__inc__rement”;
what INC does is simply increase the value of a RAM address or
register by 1. So, if we wanted to give the current player an extra
life, one way to do it would be:

INC $0DBE

$0DBE
holds the current player's lives, so INC $0DBE gives the current
player one more life. Now what about the other way around? What if we
want to make the player *lose*
a life, but without dying? For that, we use DEC. This code:

DEC $0DBE

would
*decrease*
the current player's lives by 1. But wait...what if we wanted to give
the player *ten*
more lives? With our current knowledge, you'd think that

INC $0DBE

INC $0DBE

INC $0DBE

INC $0DBE

INC $0DBE

INC $0DBE

INC $0DBE

INC $0DBE

INC $0DBE

INC $0DBE

would be the way to go. However, while that would work, it's not very efficient. There is a much shorter way. For this, we'll need two more opcodes: CLC and ADC. Using CLC and ADC, this same code would be

LDA $0DBE

CLC

ADC #$0A

STA $0DBE

That
simply loads the current player's lives into A, adds 10 (10 decimal,
which is 0A in hexadecimal, remember) to that vallue, and stores the
result back into $0DBE, the RAM for lives. ADC stands for “Add
with Carry”; the value you want to add goes directly after the
ADC. But notice something else here...CLC. There is nothing after it.
And what do you think it does? Wasn't ADC what we use for adding?
Well, you *could*
put ADC alone, but it wouldn't be a very good idea. CLC stands for
“Clear Carry Flag”, and you almost always need it right
before an ADC. What exactly is the carry flag? You don't really need
to know yet, although it is covered in lesson 3-4. The carry flag,
when used with ADC, determines whether to add the value as-is or to
*add one to it*.
If the carry flag was already clear before the ADC, then all is well.
ADC #$0A adds 0A. But if the carry flag, by chance, happened to be
*set*
before you put the ADC there, then ADC #$0A would actually add, not
0A, but *0B*!
So ADC really adds the specified value *plus*
the
carry flag, and if you don't clear that carry flag before you add
something, you could very well end up accidentally adding one more
than you mean to. Just remember that CLC should almost ALWAYS be put
before ADC.

p2.2.1

Of
course, the next question that will come up is, what do we do if we
want to give the player *negative*
ten
lives (subtract ten lives, make him/her lose ten lives)? You could
“DEC $0DBE” ten times, but you've probably figured out
that there must be a quicker way. Aaaaannnndd...there is! To *subtract*
a
number greater than 1, use SEC and SBC. To make the player lose 10,
or x0A (hexadecimal numbers are sometimes preceded by “x”
or “0x” to indicate that they are hexadecimal) lives, you
would use this code:

LDA $0DBE

SEC

SBC #$0A

STA $0DBE

Looks
almost like our previous code, doesn't it? But wait...what the?
There's another $#@%! opcode out there in the middle of nowhere! The
first, third, and fourth lines look okay: opcode, value/address. But
there's that SEC without anything after it.... As you might imagine,
the relationship of SEC to SBC is similar to the relationship of CLC
to ADC. The difference is that SEC—which stands for “Set
Carry Flag”—*sets*
the
carry flag instead of clearing it. SBC stands for “Subtract
With Carry”. Emphasis on “with carry”...just like
ADC, you can get some unwanted results if you use SBC alone. This
time, when the carry flag is *set*,
SBC subtracts exactly what you'd expect it to, which, in this case,
happens to be 0A. But what if the carry flag is clear before the SBC?
What if, just for testing purposes, we put *CLC*
SBC
instead? When the carry flag is clear, SBC actually subtracts *one
more* than
the specified value. So “CLC SBC #$0A” would subtract 0B
instead of 0A. Just remember: ADC is almost always preceded by CLC,
and SBC is almost always preceded by SEC. (Although there is that
“almost”...we'll worry about that later, in section

3-4.)
In case you were wondering, yes, you *can*
ADC
or SBC a RAM address as well as a value, just like you can INC or DEC
a RAM address. (ADC $05, for example, or SBC $066A, are acceptable.),
However, although ADC and SBC work okay with 24-bit addresses, *INC
and DEC do not*.
Keep that in mind.

p2.2.2

Oh, I almost forgot to mention something: You can increment or decrement A, X, and Y as well as RAM addresses. If you want to increase the value in A by 1, use either this:

INC A

or this:

INC

What's
the difference between INC and INC A? Not much. If you use INC
without anything after it, it counts as INC A. The same goes for DEC;
either “DEC A” or simply “DEC” works. X and Y
don't work *quite*
the
same way, but they are equally easy. To increment or decrement X or
Y, you use one of these four opcodes:

INX

INY

DEX

DEY

You can probably guess at their meanings. INX = increment X. INY = increment Y. DEX = decrement X. DEY = decrement Y. No, you can't put something like “DEC X” or “INC Y”; ASM doesn't really work that way. By the way, INC A and DEC A are the best way to subtract 1 from a long address, since you can't directly INC or DEC the address. If you want to subtract one from a long address, you can use LDA $insertaddresshere DEC A STA $insertaddresshere. Similarly, if you want to add one to a long address, you can use LDA $whatever INC A STA $whatever.

p2.2.3

Alrighty,
then. We have the addition and subtraction down okay...what about the
other two basic operations of arithmetic, multiplication and
division? Don't worry, these aren't too hard; in fact, they may be
easier than addition and subtraction in some cases. For
multiplication, use ASL. This stands for “Accumulator Shift
Left” (no,
*not* “age, sex,
and location” or even “American Sign Language”),
which likely stems
from the base command, multiplying A. ASL multiplies something by 2.
You can ASL a RAM address, or you can ASL the accumulator. These
codes are all valid:

ASL $09

ASL $0DBE

ASL A

ASL

Notice
that last one especially. Just like with INC and DEC, if you use ASL
without anything after it, it is the same as ASL A. To *divide*
something, you use LSR. LSR stands
for “Logical Shift Right.” Substituting LSR for ASL in
our four examples, we get:

LSR $09

LSR $0DBE

LSR A

LSR

Once again, when an LSR occurs by itself, “LSR A” is implied. Just as ASL multiplies something by 2, LSR divides something by 2. You can even string several ASL's or LSR's together. To multiply by 4, for example, use:

ASL

ASL

To divide by 8:

LSR

LSR

LSR

To multiply by 16 (10 in hexadecimal):

ASL

ASL

ASL

ASL

...and so on and so forth. Now, you'll probably ask, what if you want to multiply by something that isn't a power of 2? What if you want to multiply something by 3, 5, or 6, for example? Well...you can multiply a RAM address by 3 with this code:

LDA $00 (we'll use $00 as an example)

ASL A

CLC

ADC $00

A
now has the value of $00 times 3. But just try that with a number
like, say, 27. Actually, don't. You'll just give yourself a headache,
and I didn't include a free bottle of aspirin with this tutorial due
to budget cuts. There *is* a
way to multiply or divide by any number you desire, but it is more
complicated and much less well-known. You can't do it with just an
opcode alone. (Lesson 3-5 covers that, if you're curious.) So you'll
usually be multiplying and dividing only by powers of 2. Also, you
can't ASL or LSR long addresses, either. If you want to multiply
$7007FF by 2, you'd have to use

LDA $7007FF

ASL (A)

STA $7007FF

. Also, ASL and LSR have no opcodes for X and Y. You can't ASL X or LSR Y, for example. To multiply X or Y...well, in Lesson 2-3, all will be revealed.

p2.2.4

In summary:

-INC raises the value of a RAM address by 1; DEC lowers it by 1.

-INC A, INX, and INY increase the value of A, X, and Y by 1; DEC A, DEX, and DEY decrease them.

-ADC and SBC add or subtract a specified value or the value of a RAM address.

-CLC must come directly before ADC, and SEC must come directly before SBC.

-ASL multiplies an address by 2, and LSR divides it by 2.

-ASL and LSR can also be used to multiply or divide A by 2.

-If INC, DEC, ASL, or LSR are used without an address or anything else after them, “INC A”, “DEC A”, “ASL A”, and “LSR A” are assumed.

-You can't use INC, DEC, ASL, or LSR on 24-bit addresses, although you can use ADC and SBC.

__Lesson
2-3: Transferring__

__Opcodes:
TAY, TYA, TAX, TXA, TYX, TXY__

__Addressing
modes: none__

__Progress:__

21/99

4/15

ADC AND ASL BCC BCS BEQ BIT BMI BNE BPL BRA BRK BRL BVC BVS CLC CLD CLI CLV CMP COP CPX CPY DEC DEX DEY EOR INC INX INY JML JMP JSL JSR LDA LDX LDY LSR MVN MVP NOP ORA PEA PEI PER PHA PHB PHD PHK PHP PHX PHY PLA PLB PLD PLP PLX PLY REP ROL ROR RTI RTL RTS SBC SEC SED SEI SEP STA STP STX STY STZ TAX TAY TCD TCS TDC TRB TSB TSC TSX TXA TXS TXY TYA TYX WAI WDM XBA XCE

imm8/16 dp abs long dp,x abs,x abs,y long,x (dp) [dp] (dp),y [dp],y (dp,x) sr,s (sr,s),y

p2.3.0

The
good news is, this lesson is short and easy. The bad news is...hmm,
what *was* the bad news?
Your grandmother just got run over by a Mack truck? Oh, never mind.
Well, we only have six opcodes to worry about here, and as luck would
have it, they all do practically the same thing...*and*
they all have only one addressing
mode.

p2.3.1

Ahem...in
ASM, there are opcodes called *transfer* commands.
These are easiest to understand with examples. SO...remember back at
the end of paragraph 2.2.3 when I pointed out that there are no
opcodes to multiply X or Y? I mean, you can ASL A, and you can LSR A,
but you can't do that with X or Y. Wouldn't it be nice if we could
just...use A *instead* or
X or Y? Well, in a way, we can! Let's say you have a value in Y that
you want to multiply by 2. You can't ASL Y, obviously. You can ASL A,
but how can you possibly change Y into A? Easy. You transfer. To
multiply Y by 2, do this:

TYA

ASL A

TAY

The
command TYA (with nothing after it) takes whatever value is in Y and
copies it to A. (TYA: Transfer Y Register to Accumulator.) Similarly,
the command TAY (again, nothing after it) takes whatever value is in
A and copies it to Y. (TAY: Transfer Accumulator to Y Register.)
Besides TYA and TAY, you also have TAX, TXA, TYX, and TXY. As you
probably guessed, TAX transfers A to X, TXA transfers X to A, TYX
transfers Y to X, and TXY transfers X to Y. There are actually a
couple other transfer commands, but they are much less common. The
main ones are TAY, TYA, TAX, TXA, TYX, and TXY. Something to note is
that transfer commands *copy*; they don't *cut*. If you
transfer Y to A, for example, the value that was in Y isn't lost. Y
still has the same value it did before the TYA.

p2.3.2

See? Easy stuff, right? Well, watch out...the next lesson isn't quite as simple. But don't worry. I'm here to explain.

__Lesson
2-4: Branching and Conditional Statements__

__Opcodes:
CMP, CPX, CPY, BEQ, BNE, BCC, BCS, BPL, BMI, BVC, BVS, BRA, BRL__

__Addressing
modes: none__

__Progress:__

27/99

4/15

imm8/16 dp abs long dp,x abs,x abs,y long,x (dp) [dp] (dp),y [dp],y (dp,x) sr,s (sr,s),y

p2.4.0

Okay,
first off, here's a question: What if you want some code to run only
when a given condition is true? What if, say, you want a block to
give the player 20 coins *only* if
he/she has a cape? Then there's that “subtracting ten lives”
code in paragraph 2.2.1. What happens if the player has ten lives or
fewer when that code runs? His/her life count would end up at
zero...or in the negatives? To deal with situations like these, we
need some new opcodes: the compare commands and the branch commands.
Let's take our first example and make a code that gives the player 20
coins (that's 14 in hexadecimal) when he/she has a cape, but does
nothing otherwise.

LDA $19

CMP #$02

BNE Return

LDA #$14

STA $13CC

Return:

RTS

Let's
go through this code line by line. The first line is simply “LDA
$19”, which you're already familiar with. This simply loads the
player's powerup. Now, the next line...CMP #$02. Any guesses what
that does? Well, I'm gonna break the suspense: CMP stands for
“Compare”. You put a value after CMP, and it will compare
that to whatever is in A. In this case, you're using CMP to check if
the powerup status is “cape”. The next opcode here is
BNE, which stands for “Branch if Not Equal”. This means
that, if $19 is not equal to 02, the code will jump to another spot.
But notice what comes after the BNE...it's a word instead of a
number. Why BNE Return, not BNE #$04 or something? That's just how
branch commands work. The word or words after the BNE—in this
case, “Return”—are called a *label* or *symbol*.
You can use pretty much anything you want as a label. Instead of BNE
Return, that could have just as easily been BNE EndCode, BNE NoCoins,
BNE Label1...heck, I even used “FlatulentOrangutans” as a
label in a code once. However, THIS IS IMPORTANT, you need to make
sure that the label actually exists. If I had written the code like
this:

LDA $19

CMP #$02

BNE Return

LDA #$14

STA $13CC

RTS

it
wouldn't work. The BNE has nowhere to branch to, since the label
“Return” doesn't appear at another point in the code.
That “Return:” has to be somewhere else in the code, or
your game will crash...and in video games, the only time you want
“Crash” is when he's Coco's brother. Do you need the
colon after the label? Well, depends. Sometimes you don't, but it's
always best to put the label there anyway. Some things, such as
patches, *always* require it.
(It depends on what you're using to assemble your code...TRASM is the
assembler that mikeyk's Sprite Tool uses, and xkas is used for pretty
much everything else.) Anyway, in the next line of the code, we see
LDA #$14. We know what this does, ditto the next line: STA $13CC. But
remember what came *before* this
part of the code: a conditional statement, which in this case is a
CMP paired with a BNE. The lines after the BNE but before the label
“Return:” will run ONLY if the BNE did not cause the code
to branch. That is, if the player had a cape, which means that $19
would equal 02.

p2.4.1

Now
let's vary things up a bit. We've made a code that gives the player
20 coins only if he/she has a cape. But let's reverse the effect and
make a code that gives the player 20 coins *unless* he
has a cape. (You know what, I'll just use “he” from now
on. My protagonist may be female, but Mario and Luigi aren't.) To do
this, we only have to change one line, one opcode:

LDA $19

CMP #$02

BEQ Return

LDA #$14

STA $13CC

Return:

RTS

We
have changed BNE to BEQ, which stands for “Branch if Equal”.
While the conditional statement in the previous code branched if the
player *did not* have a cape, the one in this code branches if
the player *does* have a cape. Another thing I should note is
that branch statements like BEQ and BNE *do not always have to be
preceded by CMP*. The following code, for example, is perfectly
valid:

LDA $19

BEQ Return

LDA #$14

STA $13CC

Return:

RTS

With no CMP there, the BEQ simply branches if $19 was equal to 00. We could have added a CMP #$00 there, but there would be no need. This code, therefore, would give the player 20 coins unless he is small. (Small Mario: $19=00.) You can do that with BNE, too: replace the BEQ in that code with BNE to get a code that gives the player 20 coins if and only if he is small. (The branch statement skips the give-coins part of $19 is anything other than 00.)

p2.4.2

Now,
I must note something: CMP, BEQ, and BNE aren't the only opcodes you
can use in conditional statements; there are a couple related
opcodes. Take CMP, for example. CMP actually compares the value in A.
If I had put LDX $19 or LDY $19 instead of LDA, then none of the
above codes would have worked correctly because CMP only compares the
value with A, not X or Y, no matter what comes before the CMP. To
compare something with X or Y, you use CPX and CPY. What CMP is to
LDA, CPX is to LDX. The same goes for CPY and LDY. Also, there are
more branch commands out there, 8 to be exact. Six of those come in
pairs: one branches if a given condition is true, and the other
branches if that same condition is false. The branch command BCC, for
example, branches if the loaded value is *less than* the
compared value. In this code:

LDA $19

CMP #$02

BCC Return

LDA #$14

STA $13CC

Return:

RTS

...the
BCC makes the code branch if $19 is *less than* 02. If $19 is
either 00 or 01, the code will branch. If it is anything else, the
code will not branch. This code, therefore, gives the player 20 coins
if he has either a cape or firepower, which correspond to the values
02 and 03 of $19. ($19 never takes on any value other than 00, 01,
02, or 03, and if you tried to make it do so, the game would probably
screw up.) Let's change this one more time:

LDA $19

CMP #$02

BCS Return

LDA #$14

STA $13CC

Return:

RTS

BCS
is sort of the opposite of BCC. BCS makes the code branch if the
compared value is *greater than or equal to* the loaded value.
Can you guess what this code does? Yep, that's right. It gives the
player 20 coins if $19=00 or 01, or in other words, if he does not
have either a cape or firepower. (By process of elimination and
common knowledge of Mario games, that means that he is either small
or big without a powerup.) By the way, you'll notice that I didn't
mention what BCC and BCS stand for. Okay, they stand for “Branch
if Carry Clear” and “Branch if Carry Set”, which
can be kind of confusing. That's not really important, though.

p2.4.3

BEQ, BNE, BCC, BCS...what's next? That's only four, which leaves six more. The next branch statement pair that you may find useful is BPL/BMI. These stand for “Branch if Plus” and “Branch if Minus”. BPL and BMI are, oddly enough, rarely used in combination with CMP (or CPX, or CPY), and when they are, they pretty much act the same way as BCC and BCS do. BPL branches if the result of the previous operation was 00-7F (considered to be “positive”), and BMI branches if the result was 80-FF (considered to be negative). I can't give any good examples for BPL and BMI with $19, since $19 is never anything over 03 and therefore is never negative. However:

LDA #$40

BPL Label

You can do that. Since the value you loaded was between 00 and 7F, the BPL causes the code to branch. If you do something like this instead:

LDA #$90

BPL Label

The BPL will not branch because 90 is not between 00 and 7F. Similarly, if you have something to this effect:

LDA #$A8

BMI Label

The branch will be taken. If you do this:

LDA #$74

BMI Label

It won't. One interesting thing you can do with BPL is make loops. These are sections of code that repeat a specified number of times. Of course, you can use BNE, too, but for the purposes of this lesson, let's use BPL.

LDX #$03

Loop:

(insert code here)

DEX

BPL Loop

Whatever code you put in between “Loop:” and “DEX” would run exactly 4 times, unless you inadvertently changed X and didn't restore it during the code. How this works is, before the loop, X starts out at 03. You run the code the first time, and then you decrement X by 1. X is now 02. However, 02 is still positive, so the BPL makes the code jump back to the beginning of the loop. (Yes, you can branch backward.) The loop runs a second time, and X is decremented again, this time to 01. But guess what, 01 is still positive, so the BPL jumps back again. The loop runs a third time, and X is decremented again. X is now equal to 00. (Pay attention; this is the good part.) Since 00 is indeed within the range 00-7F, the BPL branches once more, and the loop runs a fourth time. X is decremented again...but wait! What do you get when you subtract one from zero? Well, negative one in most math. In ASM, however, the value simply wraps around. X is now equal to FF. Then we come to the BPL...but wait! FF isn't between 00 and 7F. X is no longer positive, so the BPL does not branch, and as a result, the code does not loop again.

p2.4.4

Coming
up next will be two of the most useless opcodes in the entire list.
We have one more pair to discuss, which is BVC/BVS. These stand for
“Branch if Overflow Clear” and “Branch if Overflow
Set”. Yes, I know that the word “overflow” does not
start with V. Please file your complaint during office hours. What is
overflow, you ask? Well, aside from BIT, which you haven't even
learned about yet, the only, the ONLY opcodes that even affect
overflow are ADC and SBC. Overflow happens when you add or subtract
two numbers and end up with a number that would be outside the range
-128 to +127 (decimal). For example, C8 plus A0 is 68, but if you
treated these values as being signed numbers, then it would be
-56+-96=-152. But you can't go beyond -128, so it wraps around and
becomes +104, or 68 in hexadecimal. Similarly, if you start out with
84 and then subtract, say, 07, that would be like taking -124 and
subtracting 7 to get -131. It's kind of difficult to
understand...yeah, I know. Sorry. At least it's something relatively
unnecessary. If you look through all.log (Super Mario World's
complete source code; very useful document, even if it is a big
honkin' 7500+ KB text file), you'll see a couple BVC's and BVS's, but
99% of the time, these two opcodes are about as useful as an air
conditioner in the Antarctic. If you can find a good solid use for
BVC and BVS, then *you* should be teaching *me* ASM. The
final two branch commands, BRA and BRL, are much more useful. Well,
BRA is, anyway. BRA branches *all* the time, no matter what you
do before it. You don't need CMP, LDA, or anything. BRL does the same
thing, but it has a longer range. BRL, though, is kind of useless as
well; although its *function* is a heck of a lot more useful
than that of BVC and BVS, the opcode itself isn't, because there is
another opcode called JMP that does almost exactly the same thing. In
fact, what a perfect transition from this lesson to the next, which
is another easy one. To summarize, if not the lesson, at least the
opcodes, though:

CMP: Compares the value loaded in A with the value following the CMP.

CPX: Compares the value loaded in X with the value following the CMP.

CPY: Compares the value loaded in Y with the value following the CMP.

BEQ: Branches to a specified label if the loaded value is equal to the compared value.

BNE: Branches to a specified label if the loaded value is not equal to the compared value.

BCC: Branches to a specified label if the loaded value is less than the compared value.

BCS: Branches to a specified label if the loaded value is greater than or equal to the compared value.

BPL: Branches if the loaded value is 00-7F.

BMI: Branches if the loaded value is 80-FF.

BVC:
Branches if the code did *not* just add or subtract two numbers
to produce a result that, if you converted the hexadecimal numbers to
signed decimal numbers, would be less than -128 or greater than 127,
but no one really gives a darn.

BVS:
Branches if the code *did *just add or subtract two numbers to
produce a result that, if you converted the hexadecimal numbers to
signed decimal numbers, would be less than -128 or greater than 127.
Big flippin' deal.

BRA: Branches all the time, no matter what happened beforehand.

BRL: Branches all the time, but has a longer range than BRA. Redundant, as you'll see in the next lesson.

__Lesson
2-5: Jumping__

__Opcodes:
JMP, JML, JSR, JSL__

__Addressing
modes: none__

__Progress:__

40/99

4/15

imm8/16 dp abs long dp,x abs,x abs,y long,x (dp) [dp] (dp),y [dp],y (dp,x) sr,s (sr,s),y

p2.5.0

Guess
what? This lesson is probably almost as easy as Lesson 2-3, maybe
even more so. We only have *four* opcodes
to worry about this time. To start...JMP. JMP is similar to BRA,
which, if you remember from the last lesson, “always branches”.
JMP pretty much does the same thing; it jumps to another part of the
code specified with a label. However, with JMP, you can also use a
16-bit address. “JMP Continue”, “JMP Label01”,
and “JMP $8430” are all valid. JMP can jump to any point
within a ROM bank (i.e. within a range of 0x8000 bytes), but it
cannot go outside a bank. If we want to jump to a place that is not
within the current bank, we use JML. You can JML to a label, or you
can JML to a 24-bit address. “JML MainCode” works, as
does “JML $028008”. (JMP and JML, if you haven't guessed,
stand for “Jump” and “Jump Long”.)

p2.5.1

Besides JMP and JML, there are two more jump instructions that are actually more useful than the first two. These are JSR and JSL. JSR and JSL are similar to JMP and JML, but there is one important difference. When you JMP/JML somewhere, it's almost as if you'd never jumped at all. The RTS/RTL at the end terminates your code entirely. When you JSR or JSL, the code ends up at the point right after the JSR/JSL itself. So, for example, take these two codes (with lines numbered for easier recognition)...

1. LDA #$01

2. STA $19

3. JMP Label

4. INC $0DBE

5. RTS

6. Label:

7. LDA #$10

8. STA $1490

9. RTS

and

1. LDA #$01

2. STA $19

3. JSR Label

4. INC $0DBE

5. RTS

6. Label:

7. LDA #$10

8. STA $1490

9. RTS

.
The first code would run the lines 1 and 2, run line 3 and jump to
line 6, run lines 7 and 8, and then end at line 9. The second code,
on the other hand, would run lines 1 and 2, run line 3 and jump to
line 6, run lines 7 and 8, run line 9, and then jump back to line 4
and end at line 5. See the difference? In the first code, lines 4 and
5 are never even run because of the jump. But since the second part
of the second code jumps *back*,
the first part of it continues and finishes. JSR and JSL can come in
handy, especially in sprites. JMP and JML, on the other hand...well,
you can't make a BTSD block without JMP, and that's exactly what
we'll do next...in your first lab!

*see imamelia's ASM tutorial – Lab 1.html for lab*

__Lesson
2-6: Indexing__

__Opcodes:
none__

__Addressing
modes: dp,x abs,x long,x abs,y__

__Progress:__

44/99

4/15

imm8/16 dp abs long dp,x abs,x abs,y long,x (dp) [dp] (dp),y [dp],y (dp,x) sr,s (sr,s),y

p2.6.0

We now
come to one of the most important lessons in this tutorial. You won't
learn any new opcodes in this lesson, but you *will* learn
some new addressing modes. Indexing is extremely useful; in
fact, it is *vital* for coding
sprites. If you've ever looked through a sprite's code, you've
probably seen some RAM addresses with “,x” or “,y”
tacked onto them, like $14C8,x. X and Y, combined with some
numbers...is this ASM or algebra class?

p2.6.1

Indexing...what basically happens when you index, instead of your opcode affecting a specific RAM address, it affects a RAM address a certain distance from where you specify depending on the value of X or Y. Confusing? Don't worry. We have examples, and we will use them. Let's say we want to index...$0695 by X. We'll go ahead and use LDA for this.

LDA $0695,x

That
is the proper way to write an indexed RAM address. You put the RAM
address, then a comma (no space), and then an X or Y right afterward
(again, no space). I'm pretty sure it doesn't matter if the X or Y is
uppercase or lowercase, although the convention is usually lowercase.
LDA $0695 always loads $0695, no matter what the value of X or Y is.
But LDA $0695,x...? In this case, the RAM address that is loaded
depends on the value of X at the moment that you load it. If X = 00,
then LDA $0695,x just loads $0695. No problem. But if X = 01, then
LDA $0695,x will actually load from $0696. If X = 02, then LDA
$0695,x actually loads from $0697. If X = 03, then LDA $0695,x loads
from $0698. See that? The value of the register you're indexing by
is, in a way, added to the base RAM address before determining which
address to load. Now, since we're indexing by X here, Y has no effect
on this. Y could be equal to 00, 01, 04, 18, 8C, FF, anything, and it
wouldn't affect “$0695,x”, because we're indexing this by
X and *only* by X. Of
course, we could certainly index it by Y if we wanted to. LDA $0695,y
would be pretty much the same thing as LDA $0695,x, except that the
RAM address that would be loaded from would depend on the value of Y
rather than X. If Y = 00, LDA $0695,y just loads from $0695. If Y =
01, LDA $0695,y loads from $0696, and so on and so forth.

p2.6.2

You may want to ask at this point, what is the point in this? If X = 02, LDX $0695,x loads from $0697. Okay, so why not just load $0697 in the first place? The simple answer is that when you index, you may not—in fact, you rarely will—know the exact value of X or Y. Besides, indexing is a lot quicker than doing it another way, as you will see. Imagine if we did this:

CPY #$00

BEQ Load0

CPY #$01

BEQ Load1

CPY #$02

BEQ Load2

CPY #$03

BEQ Load3

…

Load0:

LDA $0695

BRA StoreValue

Load1:

LDA $0696

BRA StoreValue

Load2:

LDA $0697

BRA StoreValue

Load3:

LDA $0698

StoreValue:

Ugly,
right? You think that would be a pain with *four* values,
imagine doing it with, say, 60. That's why—well, one reason,
anyway—we have indexing. As for the other reason...well, now we
come to some practical applications. Let's make a teleport block that
teleports you to a specific level, and we'll use indexing to do so.
Okay, well...what do we know about teleporting in Super Mario World?
If you've looked at any levels in Lunar Magic (and i certainly hope
you have), then you may have noticed that you can press F1 to display
the screen exits in a level. So, great, right? We'll change the
screen exit of whichever screen the player is in. Take out your
handy-dandy RAM map and go to $7E:19B8. Voilá—screen
exit stuffses. But, uh-oh...we have a problem. $19B8 isn't a single
RAM address...it's 32 of them. Why? Easy. Remember, most levels have
screens numbered from 00 to 1F. If you do the conversion correctly,
that makes 32 total screens in decimal. That explains why we need 32
bytes instead of 1. So how do we know which screen that is? Heck,
that could be any number from 00-1F. If we store to, say, $19C0,
which would represent screen 08, then our block would only work if
the player happens to be in screen 08 when he touches the block.
Blergh. But all is not lost. It's not immediately obvious from the
RAM map, but $95 holds the current screen number. What do we do with
this? That's where the indexing comes in. We want to load $19B8 *plus*
whatever screen the player is in,
right? $19B8 = screen 00, $19B9 = screen 01, $19BA = screen 02, and
so on. SO...let's do this, using level C2 as an example:

LDA #$C2

LDY $95

STA $19B8,y

If
we were just storing to $19B8, this code would be only two lines
long. But since we're indexing, we need something else...something to
set our index. We start the code by loading our screen exit value,
C2. Nothing weird there, right? “LDA #$C2” is something
we've seen before, or similar to it in any case. But now that we have
the right value in A, we need to figure out where it goes. We do this
by loading the current screen into Y. Now look at the STA and how
it's formatted...STA $19B8,y. $19B8**,y**.
The “,y” afterward tells us that the address is an
indexed one. We're taking C2 and storing it to $19B8 *plus*
whatever
the value of Y is. So, if the player is in screen 00, then $95 = 00
and Y = 00. $19B8 + 00 = $19B8, so the C2 goes into $19B8. If the
player is in screen 01, then $95 = 01 and Y = 01. $19B8 + 01 = $19B9,
so the C2 goes into $19B9. if the player is in screen 06, then $95 =
06 and Y = 06. $19B8 + 05 = $19BE, so the C2 goes into $19BE. See how
that works? By the way, if you saw this code, it would more likely be
set up like this:

LDY $95

LDA #$C2

STA $19B8,y

Notice that Y is loaded first in this case. Either way works. (Also, we technically only set half of the screen exit...the rest is determined by $19D8, another 32-byte section of RAM that would be indexed in the same way. But this was, after all, an example.)

p2.6.3

Let's try another example. We'll use a label this time! Let's make a block that makes the payer invincible! But let's add an extra twist. We'll make the invincibility last for different lengths of time depending on what the player's powerup is. We can use a table for this. But let's use X instead of Y this time, shall we?

db $42

JMP MarioBelow : JMP MarioAbove : JMP MarioSide : JMP SpriteV : JMP SpriteH : JMP MarioCape : JMP MarioFireBall: JMP TopCorner : JMP HeadInside : JMP BodyInside

MarioSide:

MarioBelow:

MarioAbove:

LDX $19

LDA InvincibilityTimer,x

STA $1490

SpriteV:

SpriteH:

MarioCape:

MarioFireball:

TopCorner:

HeadInside:

BodyInside:

RTL

InvincibilityTimer:

db $FF,$7F,$3F,$1F

When
Mario touches this block from the side, below, or above, the code
first loads the player powerup, then it loads a value depending on
what the powerup is, and then it sets the invincibility timer to
that. We'll go through this code bit by bit, but notice a couple of
things. First of all, in the previous code, we stored to an indexed
address. In this code, on the other hand, we're *loading* an
indexed address. Also, the indexed address was just a plain old RAM
address in that code. This code uses a label...and after the label,
there are four bytes at the bottom. By now, I should explain that an
indexed address is usually called a *table*.
For example, $19B8,x is a screen exit table. Now let's DIVE INTO THE
CODE! First, we load the powerup, which, if you recall, should never
be any value other than 00, 01, 02, or 03. Next, we load
“InvincibilityTimer,x”. What is “InvincibilityTimer,x”?
It's that little thing at the bottom, the part that says:

InvincibilityTimer:

db $FF,$7F,$3F,$1F

The “db” just means that these are raw bytes of ROM, not opcodes or anything like that. (It's “dcb” in TRASM format, but since this is a BTSD block, it's xkas format, therefore db.) To visualize this better, let's number the bytes of the “InvincibilityTimer:” table:

FF = byte 00

7F = byte 01

3F = byte 02

1F = byte 03

If the player is small, then $19 = 00, so:

**FF
= byte 00**

7F = byte 01

3F = byte 02

1F = byte 03

...we load FF. If the player is big, then $19 = 01, so:

FF = byte 00

**7F
= byte 01**

3F = byte 02

1F = byte 03

...we load 7F. If the player has a cape, then $19 = 02, so:

FF = byte 00

7F = byte 01

**3F
= byte 02**

1F = byte 03

...we load 3F. If the player has firepower, then $19 = 03, so:

FF = byte 00

7F = byte 01

3F = byte 02

**1F
= byte 03**

...we load 1F.

In other words, if the index is 00, then the first byte in the table is loaded; if the index is 01, then the second byte in the table is loaded; if the index is 02, then the third byte in the table is loaded, etc. This works with any table, no matter what how long it is. And since our table value goes into $1490 in this case, that means that if the player is small, he will get a star timer of FF, which is about 16 “seconds” on the game timer. If the player is big, he gets 7F invincibility time, which is about 8 “seconds”. If the player has a cape, he gets only 3F time, or about 4 seconds, and if he has firepower, he gets even less, 1F time or about 2 seconds. Cheap. Now, of course, these values aren't the be-all, end-all; if you want a less drastic change in time, you could use something like this instead:

InvincibilityTimer:

db $B0,$98,$80,$68

You could also give the player more time when he has a cape or firepower and less when he is just plain little or big, such as...

InvincibilityTimer:

db $30,$54,$78,$9C

That's
indexing for you. It comes in handy for a lot of things, believe me.
In fact, it is *vital* for
sprites...but we won't learn about that until later. By the way,
there are four different addressing modes for indexed addresses:

dp,x

abs,x

long,x

abs,y

In
other words, you can use X to index a direct (8-bit), absolute
(16-bit), or long (24-bit) address, but only an absolute address can
be indexed by Y. You can *sort* of
index a direct address by Y by simply adding 00 at the beginning,
like so:

LDA $00C2,y (or if you're doing something that requires xkas, LDA.w $00C2,y)

You cannot, however, do anything like that with a long address. If you need to index a 24-bit address, you have to use X. As I said before...that's indexing for you.

__Lesson
2-7: Bitwise Operations__

__Opcodes:
AND, ORA, EOR, TRB, TSB, BIT, ROL, ROR__

__Addressing
modes: none__

__Progress:__

44/99

8/15

imm8/16 dp abs long dp,x abs,x abs,y long,x (dp) [dp] (dp),y [dp],y (dp,x) sr,s (sr,s),y

p2.7.0

People seem to make bitwise commands more difficult than they should be, I think. They may seem daunting at first, but they really aren't that bad if you can get the concept down. Bitwise operations all have one thing in common, though: they use the individual bits of the operand (the address or value that your opcode affects, remember?) to “decide” what to do. You can think of it as 8 separate CMPs, one for each bit, if you wish. If you laid out the bits, they might look something like this:

0 1 0 1 1 0 1 0 (=5A)

1 0 0 1 0 0 1 1 (=93)

Now, there are three main bitwise opcodes. The first one is AND. AND takes the bits of the value of A, compares them with the bits of the value after the AND, and puts the new value back into A. With our two examples, this would be:

LDA #$5A

AND #$93

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

? ? ? ? ? ? ? ?

Taking each pair of bits individually, if either bit is 0, then the result will be a 0. The resulting bit will be a 1 if and only if both bits in the original pair were a 1. So, if we compare the first bit:

0 1 0
1 1 0 1 **0**

1 0 0
1 0 0 1 **1**

? ? ? ? ? ? ? ?

Here, we have a 0 and a 1, so that bit in the result will be 0.

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

? ? ? ? ? ? ? 0

If we compare the second bit:

0 1 0
1 1 0 **1** 0

1
0 0 1 0 0 **1** 1

? ? ? ? ? ? ? 0

We have a 1 and a 1, so the result is 1.

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

? ? ? ? ? ? 1 0

Comparing the third bit:

0 1 0
1 1 **0** 1 0

1
0 0 1 0 **0** 1 1

? ? ? ? ? ? 1 0

We have a 0 and a 0, so the result is 0.

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

? ? ? ? ? 0 1 0

If you do that with all right bits, then you end up with this:

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

0 0 0 1 0 0 1 0

00010010 = 12, so #$5B AND #$93 = #$12.

p2.7.1

So,
you may ask, how can AND be useful? Well, I have to admit one thing
about our example...it was pretty useless. ANDing two specific values
wouldn't do you much good. However, you *can* AND
a value and a RAM address. Let's make a code that checks if the
player is touching the ground. The RAM address $77 lets us know on
which sides the player is blocked. It is SxxMUDLR, but the UDLR is
the only part we're concerned about here. If the U bit is set, then
the player is touching the ceiling. If the D bit is set, then the
player is touching the ground. If the L bit is set, the player's left
side is touching a wall, and if the R bit is set, the player's right
side is touching a wall. If the U, D, L, and R bits are all set, the
player is feeling extremely claustrophobic. Okay...we want to check
if the player is touching the ground, right? So we're only concerned
about the D bit. The value if this bit is 04 in hexadecimal, so we
can use this code:

LDA $77

AND #$04

The AND #$04 clears out all bits but the D bit, and if you look at the binary, you'll see why:

? ? ? ? ? x ? ?

0 0 0 0 0 1 0 0

Bits
0, 1, 3, 4, 5, 6, and 7 are all 0 in the value 04, so those bits will
all be 0 in the result no matter what any of the ? bits are. But bit
2 (the one marked “x”) on the other hand...well, let's
say the player is touching the ground. Then the “x” bit
is 1, and since that bit in the AND value is also 1, the result will
be 1. If the player is in the air, he is therefore not on the ground,
so the “x” bit is 0. But if the “x” bit is 0,
then the resulting bit will be 0, because, remember, both bits have
to be 1 for the result to be 1. So LDA $77 AND #$04 can have only two
possible outcomes: A = 04 and A = 00. It will be 04 if the player is
on the ground and 00 if he isn't. At this point, I should add that
BEQ and BNE have another function: They can also be used to check if
the result of an operation is equal to zero. So if we do *this*...

LDA $77

AND #$04

BNE IsTouchingGround

...then
the BNE will jump to “IsTouchingGround:” if the player
was touching ground. The player was touching ground, therefore the
result of the AND was 04, and 04 is not zero, therefore the BNE
branches. If the player was in the air, then the result of the AND
would be 00, so the BNE would not branch. If you change the BNE to
BEQ, you can have it the other way around: the branch command
branches if the player is *not* touching
ground. AND works with any number; although 04 just happened to be a
single bit, we could just as easily, for example, check the player's
contact with the *walls* instead
of the ground.

LDA $77

AND #$03

BNE IsTouchingWall

Same
as above, but now we have *four* possible
results instead of two because we're leaving two bits in the AND
value. If the player is touching no walls at all, the result will be
00; if the player is touching a right wall, the result will be 01; if
he is touching a left wall, the result will be 02; and if he is
touching both (although that seldom, if ever, happens), the result
will be 03. In any case, whatever value we get out, it is guaranteed
not to be zero if the player is touching a wall on either side.
Finally, one last example: AND can be used to clear bits of an
address. We could, for example, make a LevelASM code that disables
spin-jumping for the entire level. One way to do this would be simply
to disable the A button. $17 and $18 hold the data that determins
whether or not the A button is being pressed; if bit 7 of either is
set, then A is being pressed. (10000000 = 80.) So we can clear that
bit by doing the following:

LDA $17

AND #$7F

STA $17

LDA $18

AND #$7F

STA $18

7F in hexadecimal is 01111111 in binary, so when we AND #$7F, we leave all bits intact except for bit 7, which represents A being pressed. Now, there is, in fact, another way to do this, using a different opcode, which I will discuss later in this lesson. But anyway, that's AND for you. One nice thing about AND is it works with all addressing modes. If you can LDA something, you can AND it.

p2.7.2

The next common bitwise opcode is ORA. ORA is almost the opposite of AND; when you compare the bits, if either bit is a 1, the result will be 1. The result will be 0 if and only if both of the original bits were 0. If we use the example from before...

LDA #$5A

ORA #$93

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

? ? ? ? ? ? ? ?

Looking at bit 0:

0 1 0
1 1 0 1 **0**

1
0 0 1 0 0 1 **1**

? ? ? ? ? ? ? ?

We have a 0 and a 1, so the resulting bit will be a 1.

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

? ? ? ? ? ? ? 1

Looking at bit 1:

0 1 0
1 1 0 **1** 0

1
0 0 1 0 0 **1** 1

? ? ? ? ? ? ? ?

We have a 1 and a 1, so the resulting bit will also be a 1.

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

? ? ? ? ? ? 1 1

Looking at bit 2:

0 1 0
1 1 **0** 1 0

1
0 0 1 0 **0** 1 1

? ? ? ? ? ? ? ?

We have a 0 and a 0, so this time, the result will also be 0. If you go through all eight bits, you get this:

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

1 1 0 1 1 0 1 1

11011011 = DB, so LDA #$5A ORA #$93 gives us a resulting value of #$DB.

p2.7.3

Now, what fun things can we do with ORA? Not many, unfortunately...I heard it sucks at Super Smash Bros., it doesn't know how to play poker, and it has too little stamina to play baseball. ORA is, however, very good at doing certain things, even if winning a hula-hoop contest isn't one of them. You can, for example, use ORA to check if any of a group of addresses are equal to zero. For instance...

LDA $1490

ORA $1497

BNE Invincible

$1490 is the star invincibility timer, and $1497 is the flashing invincibility timer (you know, when you flash right after getting hurt). We don't know what the heck either of these are when we run this code, but we do know that if either of them are not 00, the BNE will branch. Remember what ORA does...if even one bit in either of those addresses is 1, then at least one of the bits in the result will be 1, so of course, the result will not be zero...so the BNE branches. Another thing we could do is this:

LDA $73

ORA $187A

BNE ThisLabelHasAWeirdName

$73 is the flag that determines if the player is ducking, and $187A determines if the player is riding Yoshi. So if either of those conditions are true, the result of the ORA will be a non-zero value and the BNE will branch. Mind you, ORA is not limited to one address. We can, for example, make a sprite that hurts the player unless he is invincible, ducking, or riding Yoshi, or the level is ending. ($1493.)

LDA $1490

ORA $1497

ORA $73

ORA $187A

ORA $1493

BNE LeaveHimAloneYouJerk

If any of those five initial conditions are true, then the BNE will branch. The most important thing about ORA, though, is that it can set certain bits. Remember how I said AND could be used to clear bits? Well, ORA can be used to set bits. Let's say we're making a level in which we want the player to be constantly running to the right. We can use $15 for this. Bit 0 indicates whether the player is pressing Right, and bit 6 indicates whether the player is pressing Y. We want both of those set, so we can do this:

LDA $15

ORA #$41

STA $15

That will make the player act like he is pressing Right and Y all the time. As with AND, there is another way to do it in this case, but we'll discuss that later in this section. ORA, like AND, can use all addressing modes that LDA can. This means that you can ORA #$05, ORA $1471, ORA $1540,x, ORA $7F8190, and a lot more.

p2.7.4

There
is one more main bitwise opcode: EOR. After AND and ORA, EOR can look
kind of weird, but it really isn't too difficult to understand. When
you EOR two bits, the resulting bit will be 1 if one of the original
two bits was 1 *but not both*.
A 0 and a 0 gives us 0, a 0 and a 1 gives us 1, and a 1 and a 0 gives
us 1, which makes it look like ORA...but a 1 and a 1 also gives us a
0. If we use our example...

LDA #$5A

EOR #$93

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

? ? ? ? ? ? ? ?

Looking at bit 0:

0 1 0
1 1 0 1 **0**

1
0 0 1 0 0 1 **1**

? ? ? ? ? ? ? ?

We have a 0 and a 1, so the result will be 1. Looking at bit 1:

0 1 0
1 1 0 **1** 0

1
0 0 1 0 0 **1** 1

? ? ? ? ? ? ? 1

We have a 1 and a 1, so the result will be 0. Looking at bit 2:

0 1 0
1 1 **0** 1 0

1
0 0 1 0 **0** 1 1

? ? ? ? ? ? ? 1

We have a 0 and a 0, so the result will be 0. If you do that with all eight bits, you get:

0 1 0 1 1 0 1 0

1 0 0 1 0 0 1 1

1 1 0 0 1 0 0 1

11001001 = C9, so LDA #$5A EOR #$93 gives us a result of C9. Now, you probably guessed I would ask this: What is EOR useful for? FLIPPING! For example, let's say you want to make a block that switches the on/off value. The on/off switch value is determined by $14AF. If it is 00, the switch is on, and if it is anything else (usually 01), it is off. So we can do this:

db $42

JMP MarioBelow : JMP MarioAbove : JMP MarioSide : JMP SpriteV : JMP SpriteH : JMP MarioCape : JMP MarioFireBall : JMP TopCorner : JMP HeadInside : JMP BodyInside

MarioBelow:

LDA $14AF

EOR #$01

STA $14AF

MarioAbove:

MarioSide:

SpriteV:

SpriteH:

MarioCape:

MarioFireBall:

TopCorner:

HeadInside:

BodyInside:

RTL

So,
if $14AF was 00 before (read: the switch was on), it will now be 01.
But if it was 01 before (the switch was on), it will now be 00. In
fact, with EOR, you can even flip *all* the bits of something.

LDA ---

EOR #$FF

After
this, whatever was in A...every bit that was 0 before the EOR is now
1, and every bit that was 1 before the EOR is now 0. You'll
absolutely *flip out* once you know how to use EOR, believe me.
[/badpun]

p2.7.5

There
are more bitwise commands, but some of them aren't as straightforward
as AND, ORA, and EOR are. The first two are TRB and TSB. These simply
stand for “Test and Reset Bits” and “Test and Set
Bits”. They act *kind of* like AND and ORA, but not quite.
But they can be quicker in certain situations. For example, if you
wanted to clear bit 3 of an address (say, $0F40), you could do the
following:

LDA $0F40

AND #$F7

STA $0F40

#$F7 is #%11110111, so that “0” in bit 3 means that after the AND, bit 3 of whatever value is in A will invariably be clear. Then you store that value back into the address. But there is a slightly shorter way to do this:

LDA #$08

TRB $0F40

See? #$08 is #%00001000. We use A to specify which bit or bits we want to clear, and then we TRB an address to clear those. Want to clear bit 2 instead? Then do

LDA #$04

TRB $0F40

Want to do bits 0 and 7 simultaneously?

LDA #$81

TRB $0F40

TSB is
similar. In fact, it is identical...except that it *sets* the
bits instead of clearing them. So

LDA #$08

TSB $0F40

would
*set* bit 3.

LDA #$81

TSB $0F40

would set bits 0 and 7. With both TRB and TSB, whichever bits are set in A, those are the bits of the address that the TRB or TSB will affect. Unfortunately, while TRB and TSB are quicker than AND and ORA for clearing/setting bits, they have a pretty big disadvantage: they each have only 2 addressing modes. You can TRB/TSB a direct page address (e.g. TRB $15), or you can TRB/TSB an absolute address (e.g. TSB $010D)...and that's IT. No long addresses, no indexed addresses...it's a shame.

p2.7.6

Another bitwise command you can use is BIT. BIT #$-- acts sort of like AND #$--, except that it doesn't affect the value of A. If we compare these two codes:

LDA $7FAB10,x

AND #$04

BNE BitSet

and

LDA $7FAB10,x

BIT #$04

BNE BitSet

...the first code would load the value of $7FAB10,x (which, by the way, is the address holding the extra bits for custom sprites), but then the AND #$04 clears all bits of A except bit 2, so now A is either 00 or 04. If it is 00, the BNE does not branch, and if it is 04, the BNE branches. The second code, on the other hand, loads the value of $7FAB10,x and...well, if the result from the BIT #$04 was 00, the BNE doesn't do anything, and if it was 04, the BNE branches, but there is an important difference: A still holds the same value it had before the BIT. This might be 04 or 00, but it could also be 0C, 88, or 06, for example. Can you use BIT with an address rather than a value? Is, for example, BIT $77 valid? Yes, but it's a little BIT harder to use. In fact, it is so weird that having a good understanding of it would require skipping ahead to section 3-4. But don't worry. BIT isn't terribly useful; most people just use AND, which works just as well or better nine times out of ten.

p2.7.7

The last two bitwise operations aren't terribly useful; they mostly just make some things shorter. It's kind of the same principle as TRB and TSB sometimes making a code slightly shorter than it would be if we used AND or ORA. These are ROL and ROR. ROL and ROR stand for “Rotten Lemons” and “Rotten Rutabagas”...I mean “Rotate Left” and “Rotate Right”. ROL and ROR are very similar to ASL and LSR, but with one important difference. You know how, when you ASL or LSR something, if a set bit goes beyond bit 7 or 0 (depending on the direction it is being shifted), it just...disappears? Eh, maybe not. Another example we shall have.

CLC

LDA #%01101010 ; #%01101010 = #$6A

ASL ; A is now 11010100, or #$D4; the carry flag is clear

ASL ; A is now 10101000, or #$A8; the carry flag is set

ASL ; A is now 01010000, or #$50; the carry flag is set

ASL ; A is now 10100000, or #$A0; the carry flag is clear

ASL ; A is now 01000000, or #$40; the carry flag is set

ASL ; A is now 10000000, or #$80; the carry flag is clear

ASL ; A is now 00000000, or #$00; the carry flag is set

Notice
how the multiplication worked fine when A was between 00 and 7F (6A x
2 = D4, 50 x 2 = A0, 40 x 2 = 80), but when A was between 80 and FF,
we got some rather odd results. Why does ASLing D4 give us A8, which
is *less* than D4? Well,
if you open up Windows Calculator (or whatever program you have, if
you don't use Windows) and multiply D4 by 2, you get *1*A8.
This is a three-digit number, but right now, A can be only two
digits...so the initial 1 is lopped off and we get A8. Now what's
this about the carry flag? What the heck *is* the
carry flag anyway? Once again, section 3-4 answers that, but right
now, all we need to know about the carry flag is that ASL, LSR, ROL,
and ROR affect it. In the case of ASL, whatever was in bit 7 (the
highest bit) before goes into the carry flag. When we had #$D4, for
example, bit 7 was a 1, so the carry flag ended up set after the ASL.
When we had #$50, on the other hand, bit 7 was 0, so the ASL *cleared*
the carry flag. LSR would do the
same thing, only the *lowest* bit,
bit 0, goes into carry instead of bit 7. So, assuming that the carry
flag was clear beforehand (which it is, since I put a CLC there)...

First round:

76543210 C

**0**1101010
*0*

Second round:

76543210 C

**1**1010100
*0*

Third round:

76543210 C

**1**0101000
*1*

Fourth round:

76543210 C

**0**1010000
*1*

Fifth round:

76543210 C

**1**0100000
*0*

etc. The bit shown in bold goes into carry, and the bit in italics disappears completely. Now, what if we used LSR instead?

CLC

LDA #%01101010 ; #%01101010 = #$6A

LSR ; A is now 00110101, or #$35; the carry flag is clear

LSR ; A is now 00011010, or #$1A; the carry flag is set

LSR ; A is now 00001101, or #$0D; the carry flag is clear

LSR ; A is now 00000110, or #$06; the carry flag is set

LSR ; A is now 00000011, or #$03; the carry flag is clear

LSR ; A is now 00000001, or #$01; the carry flag is set

LSR ; A is now 00000000, or #$00; the carry flag is set

LSR, if anything, is easier than ASL; you don't get any funny results, just pretty straightforward division by 2, with the carry flag set if the original value was an odd number. If you use the same kind of diagram that I had before, you get this:

First round:

76543210 C

0110101**0**
*0*

Second round:

76543210 C

0011010**1**
*0*

Third round:

76543210 C

0001101**0
***1*

Fourth round:

76543210 C

0000110**1**
*0*

Fifth round:

76543210 C

0000011**0
***1*

etc. The bit in the carry flag disappears into oblivion just like it did with ASL, but this time, the lowest bit goes into carry instead of the highest.

p2.7.8

Okay, so what does all this have to do with ROL and ROR? Well, if we had used ROL in our first example instead of ASL, we would get this:

CLC

LDA #%01101010 ; #%01101010 = #$6A

ROL ; A is now 11010100, or #$D4; the carry flag is clear

ROL ; A is now 10101000, or #$A8; the carry flag is set

ROL ; A is now 01010001, or #$51; the carry flag is set

ROL ; A is now 10100011, or #$A3; the carry flag is clear

ROL ; A is now 01000110, or #$46; the carry flag is set

ROL ; A is now 10001101, or #$8D; the carry flag is clear

ROL ; A is now 00011010, or #$1A; the carry flag is set

WHOA!
What the heck? The highest bit went into carry, all right...but
instead of disappearing, it came out the other side! Yep, you heard
me correctly. With ASL, the bit that goes into carry then disappears,
but with ROL, it keeps going. With ASL, whatever was in bit 7 before
is now in the carry flag and whatever was in the carry flag before
vanishes, but with ROL, whatever was in bit 7 before is now in the
carry flag and whatever was in the carry flag before *is now
in bit 0*.

First round:

76543210 C

**0**1101010
*0*

Second round:

76543210 C

**1**1010100
*0*

Third round:

76543210 C

**1**0101000
*1*

Fourth round:

76543210 C

**0**1010001
*1*

Fifth round:

76543210 C

**1**0100011
*0*

The bold bit still goes into carry, but the italicized bit goes into bit 0 rather than disappearing. Now, what if we did it the other way? What if we used ROR instead?...

CLC

LDA #%01101010 ; #%01101010 = #$6A

ROR ; A is now 00110101, or #$35; the carry flag is clear

ROR ; A is now 00011010, or #$1A; the carry flag is set

ROR ; A is now 10001101, or #$8D; the carry flag is clear

ROR ; A is now 01000110, or #$46; the carry flag is set

ROR ; A is now 10100011, or #$A3; the carry flag is clear

ROR ; A is now 01010001, or #$51; the carry flag is set

ROR ; A is now 10101000, or #$A8; the carry flag is set

The
same thing happens, but instead of bit *7* going
into the carry flag and the carry flag going into bit *0*,
the reverse happens: bit 0 goes into the carry flag and the carry
flag goes into bit 7. An interesting thing you may notice is that
some of the hexadecimal values in the list we made with ROR are
exactly the same as those from the list with ROL. If you ROL or ROR 9
times, the result will be exactly the same as the original value,
since there are 9 bits involved.

First round:

76543210 C

0110101**0**
*0*

Second round:

76543210 C

0011010**1**
*0*

Third round:

76543210 C

0001101**0
***1*

Fourth round:

76543210 C

1000110**1**
*0*

Fifth round:

76543210 C

0100011**0**
*1*

Now you see why they are referred to as “rotating” commands. If you could put the nine bits in a circle, with C (carry flag) at the top and the 0-7 clockwise around the circle, then ROR would “turn” the bits clockwise, and ROL would “turn” them counterclockwise.

p2.7.9

Bitwise commands! They look a bit scary when you first see them; you might have been a bit alarmed when you first saw them, eh? But you don't have to fear them one bit...they're not a bit difficult to use once you're a bit more familiar with them. Just give them a bit of love; they can be quite a bit useful in some situations. I hope you've learned a bit about them. Well, with that 8-bit string of bad puns, we are officially finished with section 2. Thanks for reading!