Program Counter (PC)

Hi all!
Does anyone know how to manipulate the PC of the Atmega trough Arduino environment?
I'm making a real time multitask operative system for a university project and I have to address the PC to a location in the flash memory where I previously loaded a task.

This is a pseudoce of I want to do:

struct PCB {
  int identifier;
  int start_address;
  int execution_address;
  int process_status;
  int accumulator;
  int word_status;
};

struct partition {
  int idp;
  int start_p;
  int end_p;
  int status_p;
  int size_p;
};

PCB process[100];
int queue_process[100];
int cmd; int npc;

partition memory[100];
int cpartitions = 6;

void setup(){
for (int i = 0;i <= 5 ;i++){
memory[ i].idp = 1;
memory[ i].start_p = 4096 + 4096*i;
memory[ i].end_p = 8192 + 4093*i;
memory[ i].status_p = 0;
memory[ i].size_p = 4096;
}  //making 6 partitions of the memory of 4k-size each
}

void loop(){
//cmd = leer comando();
/*switch(cmd){
  case 1:
    load_process()
  case 2:
    download_process()
  ...
}*/
if(process[queue_process[0]].status_process == 1){
  start_Timer();
  process[queue_process[0]].status_process = 2;
  [color=red]PC = process[queue_process[0]].start_address,[/color]
}
else{
  recover_environment();
  start_Timer();
  [color=red]PC = process[queue_process[0]].execution_address;  [/color]
}
}

That's just the main part of the hole code...
I just can't figure out how to load a value to the PC.
I will be waiting for any feedback... Thanks in advance!

PC = x

That certainly won't work, AFAIK there is no way to directly change the PC on an AVR. You can call a function using the __NAKED (?) directive so you know exactly where the PC is, dork the value on the stack and return.

Bit dodgy though.


Rob

Hi Graynomad, thanks for your time.
I know PC = x won't work, that's why I'm asking in this forum another way to do that.

Process (tasks) will be added via Serial communication so I'll know where they exactly begin and end.

//making 6 partitions of the memory of 4k-size each

Which chip are you using? That's a heck of a lot of RAM.

Here's some excerpts from a monitor program I wrote a while back, it was an ISR but I think NAKED works with functions as well. You probably don't need to save all the regs.

ISR (WDT_vect, ISR_NAKED) {
  
  /////////////////////////////////////////////
  // DIY prologue so I know exactly where the
  // program counter and working registers are
  asm (
    "push r0\n"
    "in r0,0x3f\n"
    "push r0\npush r1\npush r2\npush r3\npush r4\n"
    "push r5\npush r6\npush r7\npush r8\npush r9\n"
    "push r10\npush r11\npush r12\npush r13\npush r14\n"
    "push r15\npush r16\npush r17\npush r18\npush r19\n"
    "push r20\npush r21\npush r22\npush r23\npush r24\n"
    "push r25\npush r26\npush r27\npush r28\npush r29\n"
    "push r30\npush r31\n"
  );  // 33 bytes on the stack
....

    case  CMD_PC:
       address = (byte*)(SPL + (SPH << 8));
       address += 35; // skip 33 preamble bytes, 
                      // +1 to allow for SP post decrement
                      // +1 because it seems to work ??
       resp_lo = *(address+1);
       resp_hi = *address;
       break;
....

This was used to return the PC but could also be used to change it.

I gather the "tasks" will be located in that memory you allocated, in which case you can use the address of the base of each block if I understand you correctly.


Rob

Hi again Graynomad!

I think I'm not getting what your code given does.
I've never programmed an aTmega in assembly language before and I don't understand what you mean with "__Naked". Despite this, I think that's what I'm looking for, if as you say, it could be use to modify the PC value.

Could you please explain this in detail to me? ...if it isn't bothering much. :blush:

//making 6 partitions of the memory of 4k-size each
Which chip are you using? That's a heck of a lot of RAM.

Those partitions will be made in Flash memory.

Those partitions will be made in Flash memory.

I'm not getting this, what are these partitions for?

They can't be modified dynamically so they just house static functions do they? In which case why can't you just call them?

NAKED stops the compiler from doing any preamble at the start of a function. It's the only way I know of having things placed exactly where you want them because normally the compiler will push stuff onto the stack according to what it thinks is best on the day.

But I have to say all this is sounding a bit sus,

case 1:
    load_process()
  case 2:
    download_process()

You can't "download" a process into flash memory, so as I said you may was well just call functions.


Rob

Hi!
Sorry if I can't express what I can my code to do, I'm not quite good at English.

Yeah, you are right I can't "download" anything from the flash memory =)

The OS start whit no processes/tasks inside, just with this partition in the flash. With an interface made in C# I sent a byte that is read in:

cmd = leer comando();

Then, say cmd = 1 :

load_process()

The microcontroller will look for an empty partition and with enough size (in the example given every partition have the same size so this is not so important) and then write the "code" of that process in that partition and set memory*.status_process = 1.*
When I want to download that process (cmd = 2) just clear memory*[/color] = 0 ; so the microcontroller won't execute it any more.*
When another process is load in that partition, it will be just overwritten and set again memory*.status_process = 1.*
And, as the start position, size and end position of the process is know, there will be no problem =)
Tell me if yo get what I mean, and what you recommend me to do... How can I use "NAKED" in order to address the PC?
Thanks in advance!

jcisne7:
I just can't figure out how to load a value to the PC.

Instructions such as JUMP, CALL, Branch, etc. load new values into the program counter, yes? Not sure I understand this project, but certainly some assembly code will probably be needed.

jcisne7:
I'm making a real time multitask operative system for a university project and I have to address the PC to a location in the flash memory where I previously loaded a task.

If I understand what you're trying to do, you'll be doing some of the things that the Arduino bootloader does. The bootloader, at startup, will see if there's a new sketch to download, and if so, then do that, storing the code into memory, and then transfer control to that code. If there's no new sketch to download, then it transfers control to the already stored sketch. Thus, it seems like you might find it instructive to read the code for the bootloader. I'm not sure where to point you for that.

write the "code" of that process in that partition

I still don't follow this. You cannot write into flash unless you plan to write a custom bootloader of some sort, so where are these partitions.

One of us is barking up the wrong tree I think.


Rob

I thought writing in the flash was an easy thing, maybe it would be better to write processes in the EEPROM, and... as blinking (two) leds at different frequencies is enough for the purposes of the course I think size wont be a problem (Am I right?).

Anyone of you have idea if this would be easier to implement in a PIC (18F4550)? It is being used for the rest of my classmates and it seems they are not having so much problems... =/

I thought writing in the flash was an easy thing

No.

maybe it would be better to write processes in the EEPROM

That is easy, but you can't execute code from EEPROM.

Anyone of you have idea if this would be easier to implement in a PIC (18F4550)?

I'm not that familiar with PICs but the basic principles are the same so I can't see it being any easier, but maybe.

It is being used for the rest of my classmates and it seems they are not having so much problems... =/

Maybe they are asking different questions. I can't believe they are writing a multi-tasking OS for this, yet that seems to be what you want to do.

as blinking (two) leds at different frequencies is enough for the purposes of the course I think size wont be a problem (Am I right?).

You can load parameters into EEPROM and perform different actions based on them, but you can't load code. You could even load a script into EEPROM or RAM and interpret that. But with these small AVRs you cannot load executable code anywhere unless you write a bootloader.

Maybe you should explain exactly what you need to achieve rather than assuming that writing directly to the PC is the way to go.


Rob

well , as you said.. I had to describe the process since beginning.... in the project, I have to do multitask, but the problem is that I dont know how to manipulate the "PC" of the arduino..Take for example, in the pic16f877A, i only have to change the value of the "pcl", but in the arduino I didnt find a way to manipulate the "PC" , when my process enter in a interruption, the process only returns to the line when the interrupt ocurred or in other lines before that , but i dont know how to jump to other parts of the code. This is the exactly problem that i have, i have read about the "pc" of the arduino, but its complicate to understand exactly how it works.

Then you will have to do some inline assembler, my assembler is very rusty so don't expect these to work out of the box

ISR (XXX_vect, ISR_NAKED) {
  asm (
    "pop r0\n"   // remove PC value from stack
    "pop r0\n"
    // load new PC into regs 30 and 31 (I can't remember how to reference an external C function address)
    "push r30\n"
    "push r31\n"
    "reti\n"
  );

Or maybe this, but it won't auto clear any interrupt flags or indeed re-enable interrupts

ISR (XXX_vect, ISR_NAKED) {
  asm (
    "pop r0\n"   // remove PC value from stack
    "pop r0\n"
    // load new PC into regs 30 and 31
    "ijmp\n"
  );

But you still haven't solved how you are going to download tasks into memory so until you solve that problem all this is moot. You apparently refuse to acknowledge that fact or explain exactly what has to be downloaded. Are you telling me that on a PIC you can load code into flash using a non-bootloader program?

Also there are different types of multi-tasking, you can of course do cooperative whereby each task just returns to the main loop. Has preemptive multi-tasking been specified? Even if it has the above is a 1000 miles away from working as a preeemptive task switcher, it doesn't save the machine state for a start.


Rob

Graynomad:
You cannot write into flash unless you plan to write a custom bootloader of some sort

Tangential, I guess. Where are sketch variables stored? SRAM? Or, for that matter, malloc'd space? The malloc docs don't really specifically state that, or I'm not reading it very well.

At the machine instruction level, the AVR has several instructions for changing the PC based on a run-time variable.
There are "indirect" call and jump instructions (icall and ijmp) that set the PC to the contents of the Z register (R31:30).
But the more common technique for task switching is to arrange for the correct address to be at the top of the stack, and then do a "ret" return instruction.

void start_task(int startaddr)
{
   int * stack = malloc(stacksize);
   /*
    * set up stack
    */
    *stack = startaddr;
    // Other context
    setstackpointer(stack);  // usually magic assembler code for this
} // return goes to startaddr()

(I should note that "ijmp" is most like the PIC's "mov PCL, reg" instruction, and that the stack hack, while common on MANY architectures, is usually difficult to do on PICs since their hardware stack is not directly accessible to software.)

Hello again!

After seeing some friend's codes I realized that what I was asking is not really what teacher asked us to do :lol:

Now I think I got it clearer...

Tasks code have to be previously written in the AtMega but I have to know where are they written (where they start and finish)

This is the first part... Can anyone pleas help me whit this?

I will really appreciate your comments...

Tasks code have to be previously written in the AtMega but I have to know where are they written (where they start and finish)

I recognise all the words in that sentence, but put together like that, they don't make a lot of sense.

Can you stop with the pseudo-computer science buzzwords and explain in simple terms what it is you've understood the teacher is telling you to do?

Since you predefined that there would be 6 - 4k blocks allocated why not just establish the the first or 31st (or whatever) byte of the program is the entry point and then have those addresses hardcoded into your custom loader/scheduler. You would have to have some type of flag configured so you could keep track of whether a given segment has code loaded, or preload each segment with a subroutine return and not worry about it.

your loader would have something like this

call block1
call block2
call block3
call block4
call block5
call block6

block1:
ret

block2:
ret

etc.

loaded code would overwrite teh return and the code would execute.
you could also put conditionals before the calls and only call if the bit has been set.