Your branch answers are correct. No thoughts on the number adding exercise?! Well, read on.
Binary number written >>> %$BBBBBBBB
It's '%'. (Usually. Many things depend on which assembler you use.)
easy6502 doesn't support binary at all, as far as I know.
'$' = hexadecimal.
'%' = binary.
Neither = decimal.
If you use '#' you want the value. If you leave out the '#' it's an address.
than it will copy to targeted Register as zero.
True in easy6502. Not really true in any other context, so do not rely on this. Never rely on any values in RAM/Addresses/Registers or otherwise that you didn't put there yourself, and that aren't a documented part of the hardware. Don't transfer from X without putting a known value there first, for example. Don't rely on RAM to be zero unless you are sure you stored zero there beforehand.
Some examples have read and copied from things without writing there first, but only so the focus could be on addresses rather than the values themselves.
Register A is carrying number 15, or 10 in HEX number.
$10 = 16, not 15.
===EXAMPLE 3===
LDA $01
TAX
TAY
LDY $05
TYA
---
Register A is now carrying number 1.
No. It's carrying the value inside address 1.
Register Y is being given number 5 to carry. Because Y already has number 1, it get's replaced and now it's number 5. ::: Y is now carrying number 5.
Also no. It's carrying the value inside address 5. If you don't precede the number with a '#' it's an address.
LDA $#0D
'#' has to be used before the '$'.
#$, not $#.
LDX $01
letsdoitagain:
INX
JMP letsdoitagain
---
Register X is now carrying number 1.
Nope, it's carrying the value inside address 1. I'm drilling this into your head now, it creates some obscure bugs if you don't get used to using # when you want to load a value rather than from an address.
I'm not sure I caught every error, but you totally do get it even if there are mistakes.
Anyway, next up is a new addressing mode (and a really tiny crash course on loops). We're finally getting back to the face. It's been a while, yeah?
Very early on, I mentioned how one of the differences between the registers are which instructions and addressing modes are available. And that some addressing modes wouldn't make sense for some registers. (Or, at least. I think I did! I'm not gonna look for it.)
We've done quite a lot with Absolute Addressing. That's lda $0000 or sta $0000. It deals with the value stored at the given address.
The next thing is, again, very simple. Absolute,x and Absolute,y addressing. They deal with the value stored in the address that is X or Y places away from the given address.
The syntax is LDA $????,x for absolute,x and LDA $????,y for absolute,y.
If X is zero, the result of absolute,x will be essentially identical to absolute addressing.
If Y is zero, the result of absolute,y will be essentially identical to absolute addressing.
Code: Select all
ldx #$00
ldy #$00
lda $0200;Fetch the value from address $0200.
lda $0200,x;Fetch the value from address $0200+x. Since X is 0, and $0200+0=$0200
;It will still fetch the value from address $0200.
lda $0201;Fetch the value fom address $0201.
lda $0201,y;Fetch the value from address $0201+y. Since Y is 0, and $0201+0=$0201
;It will still fetch the value from address $0201.
The magic happens when X or Y is not zero when you use the corresponding addressing mode.
I'll pause here to make one thing clear here. X or Y is added to the address itself, and then that address is used to get the actual value. X or Y is NOT added to the actual value stored inside the address.
Code: Select all
lda #$0F
sta $0200
lda #$02
sta $0201
lda #$08
sta $0202
ldx #1
lda $0200,x;A now holds the value 2. $0200+X (which holds 1) is $0201. Inside $0201 is #$02
inx;Now X = 2
lda $0200,x;A now holds the value 8. $0200+X (which holds 2) is $0202. Inside $0201 is #$08
Note that wrapping at 255 does NOT apply to the addition or X or Y to the address in this context.
Code: Select all
lda #$0B
sta $0300
ldy #$01
lda $02FF,y;$02FF+Y (which holds 1) is $0300. Inside $0300 is #$0B. So now A holds #$0B
So perhaps now you see one of the reasons for multiple registers. And also why they're slightly different. It'd be a bit weird to do LDY $0200,Y, but you can do LDY $0200,X.
What is this addressing mode useful for? It allows you to access data that is grouped in addresses. Remember how the pixels in easy6502 are in sequential addresses? Check out this code.
Code: Select all
lda #$02
ldx #$00
loop:
sta $0200,x
inx
bne loop
This makes 256 pixels of the screen red in easy6502. With your previous knowledge, you would have had to write 256 writes to do that. One for each pixel. Here there's only one write, used for all 256 pixels.
How does it work?
It gets the color to draw with in A.
It starts X with the value 0.
It stores the value in A to $0200+x, which colors one pixel red.
Then in adds one to X. Because 1 is not zero, it goes back to the loop label.
It stores the value in A to $0200+x. But because this time X is 1 and not zero, it is coloring a different pixel than before.
It does 256 pixels because eventually X gets to 255. The inx will then make it zero. And then the branch won't go to the label and the program ends.
This concept is a "loop" in programming. It's one of the fundamental concepts. They are usually set up to do the same (or nearly) the same operation on slightly different pieces of data.
And you may have already noticed how this will tie back to the face.
this post
Contains your code for the face. Any horizontal line can be done with a loop.
Let's take a look at how to turn your top horizontal line code:
Code: Select all
lda #$04
sta $0200
sta $0201
sta $0202
sta $0203
sta $0204
sta $0205
sta $0206
sta $0207
sta $0208
sta $0209
sta $020A
sta $020B
sta $020C
sta $020D
sta $020E
sta $020F
sta $0210
sta $0211
sta $0212
sta $0213
sta $0214
sta $0215
sta $0216
sta $0217
sta $0218
sta $0219
sta $021A
sta $021B
sta $021C
sta $021D
sta $021E
sta $021F
into a loop.
First, load X with how many pixels across the line is minus 1. (That is, if you want to draw 32 pixels, you must load X with 31). Then load A with the color you want. Then, store the value in A using absolute,x addressing (the address should be the one for the leftmost pixel in the horizontal line.) Then decrement X, and branch if not equal above the store. Immediately after the loop, store to the address of the leftmost pixel (using absolute addressing.)
Code: Select all
lda #$04
ldx #$1F
toplineloop:
sta $0200,x
dex
bne toplineloop
sta $0200
Way shorter, yes? And to briefly explain this one. Imagine you want to draw a 2 pixel line.
You'd load X with 1. After a single dex, there wouldn't be a branch and you've only drawn one pixel. So you draw the next one after the loop. If you had loaded X with 2, it would take two dex before the branches would stop. ETC.
Your assignment this time is to convert ALL horizontal lines in your old face code to loops like this.
PS: Perhaps this helps with the adding numbers exercise?
To be honest, I'm not entirely sure what to cover next. Most of the remaining concepts get a little denser, and I'm not sure which is best to do first.
There's pointers. (The two hardest addressing modes. One of two, I have actually never used, so I wouldn't teach it. The other one is super useful, but hard to explain immediately how. It's abstract...)
There's addition/subtraction/comparing. (This is easyish to give a quick explanation to, but hard to
really cover.)
There's signed/unsigned numbers. (The above somewhat relies on this? Hmm...)
There's bitwise logic. (Easy so long as you don't overthink it)
And the stack. (easyish to give a quick explanation to, but hard to really cover...)
I'll think about it! I guess technically the addition circuit gives you the most fun tools, and starts to get meaty... and from there bitwise logic gets easier, with those then you'll know basically all the instructions.