#define add_sto(reg, addr) LD A, (addr)
#defcont \ ADD A, reg
#defcont \ LD (addr), A

Can someone explain what this would do?
This is sort of like defining a function with parameters. For example, if in your Z80 code you called the following:

Code:
  add_sto(B, $8600)

This is what the assembler would actually assemble the code as:

Code:
  LD A,($8600)
  ADD A,B
  LD ($8600),A

It replaces any instance of "reg" with the value that you enter into the first parameter of the macro, and replaces "addr" with the value that you enter into the second parameter of the macro.
Ok, but that means any time you want to make a function you have to take the place of another thing like add_sto?
I'm kinda confused about literal and manifest constants and variables in general.
Though be careful using that for something like "add_sto(a, $8000)". That would just double the value at $8000 Wink

I'm not quite sure what you mean by literal and manifest constants. In assembly, variables are just places in memory that you use to store a value. You want to make sure it's a place where that value won't get overwritten, though. Just keep in mind that writing to/reading from memory is a bit slower than working directly with the registers and the instructions also takes up more space.

What exactly don't you understand? It can be a little complicated to get at first, but i don't know what's giving you trouble.
Thanks for that info on registers and variables.
It just seems like there is so many different ways to declare a variable, I'm not sure which one to use if I just want to make a variable called "i" and set it to 1 or false or "Cat".
The $ before the number above means it is a hexadecimal number, or a location counter?

Here is where I was reading about literal and manifest constants:
http://eeems.omnimaga.org/files/Resources/Tutorials/ASMin28Days/lesson/day03.html#lit
My confusion is what they are used for mainly. Like, why I would need to use them.

Lastly, would this line store 1000 into Var_X, and then everywhere I type Var_X it is essentially typing 1000?

Var_X: .DW 1000

And what is the difference between that and this:

trash .EQU AppBackUpScreen
and then after I created trash, how would I store a value in it?
In assembly, setting up variables is really just allocating bits of memory to store data. eg:
Code:
#define xpos $9872

What that means is that you can reference this alias called "xpos" and store data there, so if you did the following:

Code:
  ld hl,5000
  ld (xpos),hl
That would load the decimal value of 5000 into the register HL, and then load the value in register HL into the memory location referenced by "xpos", which in this case has been defined as the address $9872.

You can also use the #define instruction to define a constant for use throughout your program, eg:

Code:
#define WIDTH 96
  ld a,WIDTH
This would load the value of 96 into the register A.

Essentially, if you define something with the #define instruction, when you assemble your program, anywhere in the code that contains that defined alias (ie. "xpos" or "WIDTH" as defined above), will be replaced with the value that you've given it (ie. $9872 or 96 as above).

You also asked about the .dw instruction. That's used to store data in your code, so extending on what you wrote:

Code:
.org $8000
  ld hl,(Var_X)
  ld de,Var_X
  ret
Var_X: .dw 1000
There are two references to "Var_X" here. The register HL will be set to the value stored at the memory location of Var_X, ie. HL will now equal 1000. The register DE will be set to the value of Var_X itself. In the above code, Var_X is a location in memory, which in the above case would be $8007.

Finally, the .equ instruction works very similar to the #define instruction. The following two instructions do exactly the same thing:

Code:
#define trash AppBackUpScreen
trash .equ AppBackUpScreen
They both tell the assembler that the alias "trash" should be replaced with "AppBackUpScreen".
"Finally, the .equ instruction works very similar to the #define instruction. The following two instructions do exactly the same thing:
Code:
#define trash AppBackUpScreen
trash .equ AppBackUpScreen
They both tell the assembler that the alias "trash" should be replaced with "AppBackUpScreen"."

You are saying trash is at the memory location of appbackupscreen?

And also in the code right above the last one, what's the difference betwwen (Var_X) and Var_X, is one the actual value, and the other the memory location? And also how can you declare a variable after it's supposed to be used?
In assembly you don't really declare variables, you just pick a space in memory and use them. This can be convenient as you have a lot of flexibility and can organize your data really well and also access it a variety of different ways, but it also means you have to be careful that you are indeed reading from that variable.

A variable is nothing more than a location in memory. So in JamesV's example, yeah you could say trash is at AppBackUpScreen, but nothing was created inserted or anything. If you wanted you could leave that #define out and just use AppBackUpScreen, it would be exactly the same.

There are two ways to load immediate data into a register, the first is without the parenthesis, just putting the address or value you want to load. Ie:

Code:
ld a,10
ld bc,$8080
ld hl,Var_X

It might be helpful to know that Var_X is just another equate in your program that the assembler calculates for you. Rather than having to calculate it's address, the assembler does it for you. In JamesV's example, Var_X really only equals $8007. It just contains the address where the .dw statement is stored. So variables aren't really variables in the classic sense, there's nothing preventing you from overwriting them accidentally or re-using that area for something else. So without the parenthesis, you're just loading that value into the register (here, Var_X is the same as $8007).

The second way is called indirection. This uses parenthesis around the address, and what this does is get data stored at a certain address.

Code:
ld a,(10)
ld bc,($8080)
ld hl,(Var_X)

The first instruction loads a one-byte value stored at $000A (10 = $0A in hex). The previous example stored 10 into a, here a's value will depend on whatever byte is located at $000A. The other two instructions load a two-byte value into the register. The first byte will go into the smaller register (c and l), this is called the LSB : Least Significant Byte. The second byte (at $8081 and Var_X+1 aka $8008) will go into the larger register (b and h). This is called the MSB, or Most Significant Byte. On the z80, values are stored in a format called Little Endian (funny, no?). This basically means that the LSB (the smaller part of a number, for example the $20 in $8020) is stored first and the MSB comes after it. The .dw statement can help us explain this.

Code:
.org $8007
Var_X: .dw 1000
It'll be easier to see if we convert 1000 to hex, so that gives us $03E8. .dw $03E8. What value is stored at $8007 and what value's at $8008? You would think that $8007 would hold $03 and $8008 would hold $E8, but it's the opposite. The LSB ($ECool is stored first and the MSB ($03) second. Therefore, these two statements are NOT the same:

Code:
.db $03,$E8
.dw $03E8
These two ARE the same:

Code:
.db $E8,$03
.dw $03E8

Alright, all of that was just to explain that when you do "ld hl,(Var_X)", the byte stored at (Var_X) (which the assembler will translate to ($8007)) well get stored into l, and the byte stored at (Var_X+1) will get stored into h. So, l = $E8 and h = $03. In the instruction "ld hl,Var_X", the LSB of the ADDRESS (and not what is stored at that address!) goes into l, and the MSB goes into h. So l = $07 and h = $80.

Aaaaand (sorry for rambling!) it's also worth noting the difference between one byte and two byte registers. One byte registers: a, b, c ,d, etc. Two byte registers: bc, de, hl, ix, etc. The only one byte register that can load/store a value from/to an immediate address is a. And remember that it will only load/store one byte. ld a,(Var_X) will load $E8 into a. Two byte registers will read/store 2 bytes. This can confuse people at the beginning, because if you do this:

Code:
ld hl,10
ld (Var_X),hl
...you're really loading two bytes. l = 10 and h = 0.

In short, in assembly the concept of a variable is very loose. There are no variable types or sizes and there's no special protection against other parts of your code overwriting your variables. All a variable is is a place in RAM that any part of your program can access and potentially modify.

You might be interested in reading Kerm's topic on indirection:
http://www.cemetech.net/forum/viewtopic.php?t=1708
Ok, that helped a lot. So when you put the parenthesis around the register or the other argument, it indicates the memory location of that place, so (hl) means the memory location hl is storing and (1337) would mean at address 1337. Right?
MrIdrik wrote:
Ok, that helped a lot. So when you put the parenthesis around the register or the other argument, it indicates the memory location of that place, so (hl) means the memory location hl is storing and (1337) would mean at address 1337. Right?


That's correct Smile
Awesome. Thanks again.
The one inconsistency is jp (hl) - this means ld pc,hl and not ld pc,(hl) as you might otherwise assume.
Though i think using indirection there would really have been more useful Razz
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement