The

`#` is needed when you want to tell the assembler/6502 to use an immediate value (think "literal number") in the operand itself, rather than "an address (in RAM or ROM) to read/write to/from". It's not a prefix used to represent base of numbers (e.g.

`$` for hexadecimal or

`%` for binary), or "types" of numbers on a per-number or per-variable basis. Better explained in code with comments:

Code: Select all

```
FOO = $01
BAR = $02
UGH = $0a
DERP = %11111110
HOBER = 26
lda FOO ; equivalent to lda $01 -- reads value from RAM location $01 and puts it into the accumulator -- assembles to a5 01
lda #FOO ; equivalent to lda #$01 -- puts the literal value 1 ($01) into the accumulator -- assembles to a9 01
lda FOO+BAR ; equivalent to lda $01+$02, i.e. lda $03 -- assembles to a5 03
lda #FOO+BAR ; equivalent to lda #$01+$02, i.e. lda #$03 -- assembles to a9 03
lda DERP ; equivalent to lda %11111110 or lda $fe -- assembles to a5 fe
lda #DERP ; equivalent to lda #%11111110 or lda #$fe -- assembles to a9 fe
lda HOBER ; equivalent to lda 26 or lda $1a -- assembles to a5 1a
lda #HOBER ; equivalent to lda #26 or lda #$1a -- assembles to a9 1a
lda HOBER*2 ; equivalent to lda 26*2 or lda 52 or lda $1a*2 or lda $34 -- assembles to a5 34
lda HOBER*100 ; equivalent to lda 26*100 or lda 2600 or lda $1a*100 or lda $0a28 -- assembles to ad 28 0a
lda #HOBER*100 ; equivalent to lda #26*100 or lda #2600 -- will fail to assemble because 2600 is too large; values can only be 0-255 (8-bit)
lda $HOBER ; undetermined -- behaviour may vary per assembler depending on parser; might do lda $26 or might do lda $1a or might throw an error
lda #$HOBER ; undetermined -- behaviour may vary per assembler depending on parser; might do lda #$26 or might do lda #$1a or might throw an error
lda #(UGH+16)*8 ; let's expand variables, use decimal rather than hexadecimal, and break the math down:
; ($0a+16)*8 == (10+16)*8 == 26*8 == 208
; thus this is the equivalent to lda #208 or lda #$d0 -- assembles to a9 d0
lda ((UGH+3)*$1000)+10 ; let's expand variables and break the math down piece by piece, in order of operation, and do some base conversion:
; ($0a+3) == (10+3) == 13 == $0d
; ($0d*$1000) == $d000
; $d000+10 == $d00a
; thus this is the equivalent to lda $d00a -- assembles to ad 0a d0
```

It's important to understand two things here (#1 may help you):

1. The CPU uses

completely different instructions/opcodes depending on what addressing mode you're using. For example,

`lda #$05` uses immediate addressing, which assembles to bytes

`a9 05`. But

`lda $05` would use zero page addressing and assemble to

`a5 05` -- note the difference of the first byte! Same goes for absolute addressing, where

`lda $1234` would assemble to

`ad 34 12`.

2. The mathematics you see above is being done

at assemble-time, calculated the assembler and NOT done at run-time by the CPU. There's a world of difference between the two. Doing mathematics on the 6502 at run-time is a substantially more involved process (simple addition/subtraction is easy, multiplying/dividing by 2/4/8/16/32/64/128 is easy, anything else is much more advanced).

Does this help?

One thing that will confuse you: you'll see parenthesis

`()` used for mathematical order-of-operation, but you'll also see it in instructions like

`lda ($16),y`. The latter isn't assemble-time mathematics being done by the assembler -- it's real/actual 6502 code using a form of indirect addressing (already discussed). This can add to some confusion as I'm sure you can imagine.

"So how does the assembler know when to use

`()` for instructions and when to use it for math?" It varies per assembler, and you have to read the assembler's documentation to get a feel for it. Some assemblers like NESASM actually use brackets

`[]` to represent the instruction-level addressing mode, and uses parenthesis purely for assemble-time mathematics. Other assemblers are smart/intelligent enough to know what you want.

If this paragraph is confusing, then I'll make it simple: in most assemblers you'd say

`lda ($16),y` or

`lda ($16,x)` or

`jmp ($1234)` to do indirect addressing, while in NESASM you'd need to write

`lda [$16],y` or

`lda [$16,x]` or

`jmp [$1234]`. NESASM tends to be "the odd man out" in this respect, and this major difference can cause a lot of problems for both newbies and experienced programmers.