Stack Tutorial
108 Coders :: General :: Tutorials
Page 1 of 1
Stack Tutorial
Introduction
I am not totally sure how useful this is to most average PSP users, but if you are interested than this is something you should definitely learn. Do not allow this to strike fear in your eyes, fear not, the stack is relatively easy once you get the hang of operating it. So if you are even slightly interested I suggest you read on cowboy, there's a lot to learn but I will only cover the basics, as everyone knows you need to figure the rest out by yourself via playing with code. A little MIPS knowledge for commands is required.
Basic Info
What is the stack you ask? Well for those of you who do not know, it is an area in memory where many useful actions can be done, and generally if you understand a little bit about what your doing you can write code to your stack using pointers etc to get a desired effect. The stacks location in user mode(space)(not sure what it is for kernal?) is located at the address 0x0XXXXXX. As you can see it is located quite high in memory. EVERY stack must have its pointer, the stack pointer aka $sp. The stack pointer draws as you will to an area of RAM that is allocated by almost every bit of code in that mode and allocates all of its data, saved/preserved registers etc. The stack also follows the basis of MIPS, and that being its offset, so it counts 00, 04, 08, 0c and so on.
Keeping your stack clean
Some find it important, some coders do not. Personally I do. What I mean by "keeping your stack clean" is keeping it as organized as possible and when allocating your data that you do it in order, such as if you were going to use the t0-t1 and then a0 for pointers in vram you would do it like so.
Code:
Writing to the stack
Once you have an idea of what you are doing, it would be in your best interest to make a blueprint of how your code is going to operate so that you can make it as functional as possible, also it is highly helpful to writing our first command, stack allocation. This is how many bytes of data we are going to barrow from the stack for use, this is how we would do so.
Code:
This simple command will remove 10 from the stack pointer for our use. Next we must allocate the registers which is quite simple and also a good example why its crucial to plan out what you are going to do because you should plan out what registers you will need and for what, overdrawing registers(allocating ones you wont use) is not smart as it wastes space, so instead of being lazy and using everything, just take what you need, and only what you need.
Since I will be using a jump or similar command in this tutorial, remember from above, you MUST save the ra before anything.
Code:
The sw command allocates that data contained in that specified register for use. Where as $0000(sp) is the offset from the stack pointer so $sp +0000 is how I used to think of it when I started.
Next we are to allocate the rest our data so here are the arguments for that, please keep in mind the offset from the stack pointer adding the value of 4 as the offset for every register we allocate.
Code:
Now this is where you implement your actual commands and code, this is what you are actually writing to the stack, well technically its basically you are taking the data from the stack and doing something with it, such as, modding or increment/decrement a float value, add, subtract, load, store etc. For the sake of time and simplicity I will simply load and store than use a random pointer(cant think of how I can use one in this tutorial without man handling DMA)
So if you know any basic MIPS(look at my previous tutorials) than this should be a breeze!
Code:
Now lets store and add some value
Code:
Now here is what we have so far:
Code:
Now let us add some more storing data and of course a random pointer
Code:
Now remember if you don't add the ra at the begging you are most likely going to crash, simple mistake can cause so much frustration? Links to your choice of a dead-zone.
Code:
NOW SINCE YOU JAL'd you MUST ADD A nop before re adding the data back to the stack.
Code:
Now of course since we borrowed from the stack, we must complete this routine by being a good neighbor and returning what we borrowed to its respective owner. Same as above, except instead of sw we lw it, again keep it clean!
Code:
Now of course we only now just gave it back, we must sign our name as a thank you for the return to complete. To do this in shortbread really all it is a simple return so, simply put...
Code:
No we are not all done, one last thing to do, I bet you can guess it?
Code:
I am not totally sure how useful this is to most average PSP users, but if you are interested than this is something you should definitely learn. Do not allow this to strike fear in your eyes, fear not, the stack is relatively easy once you get the hang of operating it. So if you are even slightly interested I suggest you read on cowboy, there's a lot to learn but I will only cover the basics, as everyone knows you need to figure the rest out by yourself via playing with code. A little MIPS knowledge for commands is required.
Basic Info
What is the stack you ask? Well for those of you who do not know, it is an area in memory where many useful actions can be done, and generally if you understand a little bit about what your doing you can write code to your stack using pointers etc to get a desired effect. The stacks location in user mode(space)(not sure what it is for kernal?) is located at the address 0x0XXXXXX. As you can see it is located quite high in memory. EVERY stack must have its pointer, the stack pointer aka $sp. The stack pointer draws as you will to an area of RAM that is allocated by almost every bit of code in that mode and allocates all of its data, saved/preserved registers etc. The stack also follows the basis of MIPS, and that being its offset, so it counts 00, 04, 08, 0c and so on.
Keeping your stack clean
Some find it important, some coders do not. Personally I do. What I mean by "keeping your stack clean" is keeping it as organized as possible and when allocating your data that you do it in order, such as if you were going to use the t0-t1 and then a0 for pointers in vram you would do it like so.
Code:
- Code:
#Clean code
sw ra, $0000(sp) !You MUST store your return if you have any type of 'jump' or carry over command i.e. jal, j, beq and so on.
sw t0, $0004(sp)
sw t1, $0008(sp)
sw a0, $000c(sp)
#Messy code
sw ra, $0000(sp)
sw t1, $0004(sp)
sw a0, $0008(sp)
sw t0, $000c(sp)
Writing to the stack
Once you have an idea of what you are doing, it would be in your best interest to make a blueprint of how your code is going to operate so that you can make it as functional as possible, also it is highly helpful to writing our first command, stack allocation. This is how many bytes of data we are going to barrow from the stack for use, this is how we would do so.
Code:
- Code:
stack
addiu sp, sp, $fff0(-0x10)
This simple command will remove 10 from the stack pointer for our use. Next we must allocate the registers which is quite simple and also a good example why its crucial to plan out what you are going to do because you should plan out what registers you will need and for what, overdrawing registers(allocating ones you wont use) is not smart as it wastes space, so instead of being lazy and using everything, just take what you need, and only what you need.
Since I will be using a jump or similar command in this tutorial, remember from above, you MUST save the ra before anything.
Code:
- Code:
stack
addiu sp, sp, $fff0(-0x10)
sw ra, $0000(sp)
The sw command allocates that data contained in that specified register for use. Where as $0000(sp) is the offset from the stack pointer so $sp +0000 is how I used to think of it when I started.
Next we are to allocate the rest our data so here are the arguments for that, please keep in mind the offset from the stack pointer adding the value of 4 as the offset for every register we allocate.
Code:
- Code:
stack
addiu sp, sp, $fff0(-0x10) //subtracts 10 from the stack pointer
sw ra, $0000(sp) //needed if we use a jump, or other similar command
sw t0, $0004(sp) //allocates the data contained in temporary register 0, with the offset of 0x0004 from the stack pointer
sw t1, $0008(sp) //allocates the data contained in temporary register 2, with the offset of 0x0008 from the stack pointer
sw a0, $000c(sp) //allocates the data contained in argument register 0, with the offset of 0x000c from the stack pointer
Now this is where you implement your actual commands and code, this is what you are actually writing to the stack, well technically its basically you are taking the data from the stack and doing something with it, such as, modding or increment/decrement a float value, add, subtract, load, store etc. For the sake of time and simplicity I will simply load and store than use a random pointer(cant think of how I can use one in this tutorial without man handling DMA)
So if you know any basic MIPS(look at my previous tutorials) than this should be a breeze!
Code:
- Code:
lui t0, $aaaa //loads first half of the data into t0
Now lets store and add some value
Code:
- Code:
addiu t1, t1, $2012
sw t1, $bbbb(t0) //loads the second half of data into t1, combining it with the data stored in t0 making it the value(0xaaaabbbb)
Now here is what we have so far:
Code:
- Code:
stack
addiu sp, sp, $fff0(-0x10) //subtracts 10 from the stack pointer
sw ra, $0000(sp) //needed if we use a jump, or other similar command
sw t0, $0004(sp) //allocates the data contained in temporary register 0, with the offset of 0x0004 from the stack pointer
sw t1, $0008(sp) //allocates the data contained in temporary register 2, with the offset of 0x0008 from the stack pointer
sw a0, $000c(sp) //allocates the data contained in argument register 0, with the offset of 0x000c from the stack pointer
lui t0, $aaaa //loads first half of the data into t0
addiu t1, t1, $2012 //adds in a little mix of doom's day(no I dont believe in it)
sw t1, $bbbb(t0) //loads the second half of data into t1, combining it with the data stored in t0 making it the value(0xaaaabbbb)
Now let us add some more storing data and of course a random pointer
Code:
- Code:
sw a0, $0500(t0) //storing a little randomness, just to use a0, lulz
Now remember if you don't add the ra at the begging you are most likely going to crash, simple mistake can cause so much frustration? Links to your choice of a dead-zone.
Code:
- Code:
jal $deadbeef
NOW SINCE YOU JAL'd you MUST ADD A nop before re adding the data back to the stack.
Code:
- Code:
nop //bye
Now of course since we borrowed from the stack, we must complete this routine by being a good neighbor and returning what we borrowed to its respective owner. Same as above, except instead of sw we lw it, again keep it clean!
Code:
- Code:
lw ra, $0000(sp) //needed if we use a jump, or other similar command
lw t0, $0004(sp) //adds the data contained in temporary register 0, with the offset of 0x0004 back onto the stack
lw t1, $0008(sp) //adds the data contained in temporary register 2, with the offset of 0x0008 back onto the stack
lw a0, $000c(sp) //adds the data contained in argument register 0, with the offset of 0x000c back onto the stack
Now of course we only now just gave it back, we must sign our name as a thank you for the return to complete. To do this in shortbread really all it is a simple return so, simply put...
Code:
- Code:
jr ra //return: all done?
No we are not all done, one last thing to do, I bet you can guess it?
Code:
- Code:
addiu sp, sp, $0010 //adds the value of 10 we borrowed back onto our beloved stack!
108 Coders :: General :: Tutorials
Page 1 of 1
Permissions in this forum:
You cannot reply to topics in this forum