This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I am trying to build a very simple operating system in assembler for my MSP430. I want to use a preemptive scheduler and go round the tasks in a round robin fashion. All of the tasks will operate indefinitely so I am not interested in any fancy prioritisation or wait states.
I have looked at an example implementation in C so I have quite a good grasp of the order that things have to happen in. I am struggling a bit to divide the available RAM into stacks for each task though.
In the C implementation:
stack_pointer[0] = initialise_stack(task1, &task1ram[STACK_TOP]); stack_pointer[1] = initialise_stack(task2, &task2ram[STACK_TOP]); stack_pointer[2] = initialise_stack(task3, &task3ram[STACK_TOP]);
Each stack is just an array of RAM, so the stack pointer is set to the first address.
In assembler though, I don't know where in memory my stack will be located. Is it bad practice to just divide up the RAM on paper and hard code addresses for each stack pointer?
For example, can I just say:
;------------------------------------------------------------------------------- RSEG CODE ; Assemble to Flash memory RSEG CSTACK DC16 0x20E4 DC16 0x21E4 DC16 0x22E4 ;-------------------------------------------------------------------------------
Where each of the constants is a hard coded memory location where I want my three stacks to begin. I then want to just set my stack pointer to one of these constants when I do a context switch and then restore the rest of the context using:
restoreContext: pop r15 pop r14 pop r13 pop r12 pop r11 pop r10 pop r9 pop r8 pop r7 pop r6 pop r5 pop r4 reti
So my question's are:
Does anyone have a good example of a simple scheduler in assembler?
What is the recommended way to divide up the RAM into stacks and produce the stack pointers?
Thanks for the reply.
I will check out Miro Samek's SST when I revisit this project.
As for defining the stacks, I see what you mean about defining them as arrays and letting the linker figure it out and I have seen this done in C. However, I am not sure how I would go about this in assembler. My approach so far has been to use the C code debugger to find out where it puts the arrays and then try to use those addresses in my assembler implementation.
The example C code I have declares 3 stacks using arrays:
uint16_t task1ram[STACK_SIZE]; //Stack size = 128 uint16_t task2ram[STACK_SIZE]; uint16_t task3ram[STACK_SIZE];
Then it gets the start address using:
stack_pointer[0] = initialise_stack(task1, &task1ram[STACK_TOP]); stack_pointer[1] = initialise_stack(task2, &task2ram[STACK_TOP]); stack_pointer[2] = initialise_stack(task3, &task3ram[STACK_TOP]);
The result of this code is that stack_pointer[] takes the values: 0x20E4, 0x21E4, 0x22E4
Cross checking this with the device data sheet shows that these are indeed three blocks of memory in RAM, each one 256B long and all one after the other.
This is exactly what I would like to have in assembler but I am unsure how to get and store these three addresses.
Should I use an RSEG and let the linker put each block where it wants or should I force them to go to the same addresses as the C compiler did?
One option is to get the C compiler to generate an assembly listing file, or keep the generated assembly language file. You can see what assembler statements to use for some example C code.Euan Andrew said:This is exactly what I would like to have in assembler but I am unsure how to get and store these three addresses.
If you are using the TI MSP430 Compiler, in the project properties under Build -> MSP430 Compiler -> Advanced Options -> Assembler Options are the options to get the C compiler to generate an assembly listing file or keep the generated assembly language file.
**Attention** This is a public forum