Bootloader for DZ60

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Bootloader for DZ60

5,645 Views
shadoooo
Contributor I
Hello.
I'm adding a bootloader to my application, I developed for MC9S08DZ60.
Basically I have some routines on the protected area of the flash, which contains the bootloader and obviuosly the standard IRQ table, and then the user application on the non protected flash. The IRQ table is duplicated, so I need to redirect the event calls when the bootloader is not active, or to pass event control to the bootloader routines when it is enabled by user application for flash uploading.
At the beginning I thought to use the flag FNORED on NVOPT to switch between the vector tables, but then I saw that FOPT is not write-accessible by code, so I decided to use a set of calls to redirect execution to the user application table when bootloader is disabled. I left FNORED to 1, so the bootloader always filters the event calls.
The main table is so defined:

void (* const _BOOT_vect[])() @0xFFC0 = {   /* Interrupt vector table */
         Bootload_ISR_31,                /* Int.no. 31 Vacmp2 (at F9C0)                Unassigned */
         Bootload_ISR_30,                /* Int.no. 30 Vacmp1 (at F9C2)                Unassigned */
         Bootload_ISR_29,                /* Int.no. 29 Vcantx (at F9C4)                Unassigned */
         Bootload_ISR_28,                /* Int.no. 28 Vcanrx (at F9C6)                Unassigned */
         Bootload_ISR_27,                /* Int.no. 27 Vcanerr (at F9C8)               Unassigned */
       ...
         Bootload_ISR_06,                /* Int.no.  6 Vtpm1ch1 (at F9F2)              Unassigned */
         Bootload_ISR_05,                /* Int.no.  5 Vtpm1ch0 (at F9F4)              Unassigned */
         Bootload_ISR_04,                /* Int.no.  4 Vlol (at F9F6)                  Unassigned */
         Bootload_ISR_03,                /* Int.no.  3 Vlvd (at F9F8)                  Unassigned */
         Bootload_ISR_02,                /* Int.no.  2 Virq (at F9FA)                  Unassigned */
         Bootload_ISR_01,                /* Int.no.  1 Vswi (at F9FC)                  Unassigned */
         Bootload_Main          /* Int.no.  0 Vreset (at F9FE)                Reset vector */
 };
 
where the functions are:

void Bootload_ISR_01(void) { asm ("LDHX 0xF9FC; JMP ,X"); };
void Bootload_ISR_02(void) { asm ("LDHX 0xF9FA; JMP ,X"); };
void Bootload_ISR_03(void) { asm ("LDHX 0xF9F8; JMP ,X"); };
void Bootload_ISR_04(void) { asm ("LDHX 0xF9F6; JMP ,X"); };
void Bootload_ISR_05(void) { asm ("LDHX 0xF9F4; JMP ,X"); };
void Bootload_ISR_06(void) { asm ("LDHX 0xF9F2; JMP ,X"); };
void Bootload_ISR_07(void) { asm ("LDHX 0xF9F0; JMP ,X"); };
...
void Bootload_ISR_26(void) { asm ("LDHX 0xF9CA; JMP ,X"); };
void Bootload_ISR_27(void) { asm ("LDHX 0xF9C8; JMP ,X"); };
void Bootload_ISR_28(void) { asm ("LDHX 0xF9C6; JMP ,X"); };
void Bootload_ISR_29(void) { asm ("LDHX 0xF9C4; JMP ,X"); };
void Bootload_ISR_30(void) { asm ("LDHX 0xF9C2; JMP ,X"); };
void Bootload_ISR_31(void) { asm ("LDHX 0xF9C0; JMP ,X"); };

while the user application table is that created by P&E (relocated):

void (* const _vect[])() @0xF9C0 = {   /* Interrupt vector table */
         Cpu_Interrupt,                /* Int.no. 31 Vacmp2 (at F9C0)                Unassigned */
         Cpu_Interrupt,                /* Int.no. 30 Vacmp1 (at F9C2)                Unassigned */
         Cpu_Interrupt,                /* Int.no. 29 Vcantx (at F9C4)                Unassigned */
         Cpu_Interrupt,                /* Int.no. 28 Vcanrx (at F9C6)                Unassigned */
         Cpu_Interrupt,                /* Int.no. 27 Vcanerr (at F9C8)               Unassigned */
       ...
         Cpu_Interrupt,                /* Int.no.  6 Vtpm1ch1 (at F9F2)              Unassigned */
         Cpu_Interrupt,                /* Int.no.  5 Vtpm1ch0 (at F9F4)              Unassigned */
         Cpu_Interrupt,                /* Int.no.  4 Vlol (at F9F6)                  Unassigned */
         Cpu_Interrupt,                /* Int.no.  3 Vlvd (at F9F8)                  Unassigned */
         Cpu_Interrupt,                /* Int.no.  2 Virq (at F9FA)                  Unassigned */
         Cpu_Interrupt,                /* Int.no.  1 Vswi (at F9FC)                  Unassigned */
         _EntryPoint                   /* Int.no.  0 Vreset (at F9FE)                Reset vector */
 };


The execution is propagated correctly to the right user routines, but there's something non working on the return addresses, because after the IRQ calls the execution goes out of the rails.
Where is the error?
Is there a better management possible for this kind of application?
Thanks in advance
Labels (1)
0 Kudos
14 Replies

1,902 Views
kef
Specialist I
I believe it should be not
 
   void Bootload_ISR_01(void) { asm ("LDHX 0xF9FC; JMP ,X"); };
   ...
 
but
 
 
   void Bootload_ISR_01(void) { asm ("LDHX #0xF9FC; JMP ,X"); };
   ...
 
or just
   void Bootload_ISR_01(void) { asm ("JMP 0xF9FC"); };
   ...
0 Kudos

1,902 Views
bigmac
Specialist III

Hello,

 

I might suggest the following code example.

 

interrupt void Bootload_ISR_01( void){   asm {      ldhx  #0xF9FC;  // Vector location      ldhx  ,x        // Fetch vector contents       jsr   ,x        // Execute interrupt function   }}

With the use of the interrupt function, the H-register should be automatically saved, and then restored immediately prior to the function exiting with a RTI instruction, where the other registers are also restored.  To keep the stack balanced, the function vectored at 0xF9FC should be called as a normal function, rather than a direct jump.  This should exit using a RTS instruction.

 

Regards,

Mac

 

0 Kudos

1,902 Views
Punit
Contributor III

Hello,

 

I tried using the above code, but still the same issue. Application stops at the point where Vector tables are concerned. Following is what I am using(I have two SEPERATE programs in Flash):

 

I have Bootloader.S19 which I load into Flash with programmer.

I have vector tables at default place ie FFC4.

 

I have Application.S19 which is loaded in the Flash through USB by my Bootloader code already present in the Flash.

I have relocated vector tables for my Application code ie at DFC4 (as 8k protected). However, as I can not write to NVOPT register therefore I need to manually redirect vector tables from FFC4 to DFC4.

 

 

**********************************************

 

In Bootloader code, in Vector.c I am doing:

 

interrupt void Bootload_ISR_1(void)
{
   asm
   {
    ldhx  #0xDFC4;  // Vector location
    ldhx  ,x        // Fetch vector contents
    jsr   ,x        // Execute interrupt function
   }
}

 

void (* near const _BOOT_vect[])(void) @0xFFC4 = { /* Interrupt vector table */
         Bootload_ISR_1,

         ...........................

}

 

void (* near const _vectReset[])(void) @0xFFFE = { /* Interrupt vector table */
        _EntryPoint                    /* Int.no.  0 Vreset (at FFFE)                Reset vector */
};

 

 

**********************************************

In Application code for Interrupt functions:

instead of:

ISR(AS1_InterruptTx)

{

}

 

I am using:

void AS1_InterruptTx()

{

}

0 Kudos

1,902 Views
Punit
Contributor III

If I look at the dissassembly of the function:

 

interrupt void Bootload_ISR_1(void)
{
   asm
   {
    ldhx  #0xDFC4;  // Vector location
    ldhx  ,x        // Fetch vector contents
    jsr   ,x        // Execute interrupt function
   }
}

 

 

Looks like this:

    [2]             PSHH  
  266:     asm
  267:     {
  268:      ldhx  #0xDFD8;  // Vector location
  0001 45dfd8   [3]             LDHX  #-8232
  269:      ldhx  ,x        // Fetch vector contents
  0004 9eae     [5]             LDHX  ,X
  270:      jsr   ,x        // Execute interrupt function
  0006 fd       [5]             JSR   ,X
  271:     }
  272:  }
  0007 8a       [3]             PULH  
  0008 80       [9]             RTI  

 

 

If you note the text in Red, instead of 57304 it shows "-8232"

 

Im not good in assembly please improve the code here.

 

 

Thanks

0 Kudos

1,902 Views
rocco
Senior Contributor II

Hi Punit,

 

-8232 is equal to 57304. The former is simply the signed representation of the latter. So that is not the problem, although I don't know what is.

 

That ISR looks correct. Are you sure that location DFD8 is pointing correctly into your service routine?

0 Kudos

1,902 Views
Punit
Contributor III

Yes, I can confirmed this by looking into my application's S19 file and ROM in the debugger, values are same. Also, confirned with the map file.

 

However, what I found is that location DFD8 contains 8 - bit address(ex 24) and DFD9 contains another 8 bit address(ex 78) so altogether we need 16-bit address (ex  0x2478) to jump to. If this is the case can you please edit the assembly code you provided.

0 Kudos

1,902 Views
peg
Senior Contributor IV

Hello

 

Yes, this is correct.

LDHX does a 16-bit fetch, the value at the specified address and the one 1 more than it. So it is doing what is expected here.

This 16-bit value in the H:X registers is then used as an offset from zero to JSR to.

 

0 Kudos

1,902 Views
Punit
Contributor III

OK.

 

Just to confirm here. My application code has vectors relocated at 0xDFC4 and the functions are not ISR functions but normal functions which are called from the ISRs in Bootloader.

Are there some other changes need to be done in the Application code as it is a seperate program. Will variable and other initializations happen automatically, as I am jumping to an address?

0 Kudos

1,902 Views
Punit
Contributor III

I found out that the Interrupt function in Application was still behaving as an Interrupt function although I changed the name from ISR(AS1_InterruptTx) to void AS1_InterruptTx(). So, I RENAMED it and declared in Vector.c. It worked then.

0 Kudos

1,902 Views
NewSteve
Contributor I

In this way, you only have one ISR (interrupt service rountine) that is located in unprotected flash, and two different vector tables will eventually points to same ISR function, don't you?

0 Kudos

1,902 Views
shadoooo
Contributor I
hm, no...
in Bootload_ISR_01 I want to jump to the 16bit address that's written on flash at address 0xF9FC.
So basically I read the 16bit address from flash (in user application IRQ table) into H:X and then I jump to H:X itself. This jump works (debugger verified), but the application crashes...
I have the new idea that maybe the fact that the H register is not saved by the ISR caller but it's used by me could be a problem....
0 Kudos

1,902 Views
shadoooo
Contributor I
yes, I did the trick!

Now the Bootload_ISR_01 routines are somethi8ng like this:

            LDX  $F9FD
            PSHX
            LDX  $F9FC
            PSHX
            RTS        

using PUSHes and RTS I do a JUMP on 16bit index without using the H register. And it works.
It's only annoying because I have to use 31 routines of 5 operations each to do a simple shadownign of IRQ.
Maybe there's a more simple method to do the same?
Any advice from HCS08 gurus?
0 Kudos

1,902 Views
Punit
Contributor III

Hi shadoo, I am also in a similar trouble and found this solution of what I wanted to implement. I tried to implement the way stated, however, my application doesn't work. Once again seems to be an Interrupt vector issues.  Would this solution also works for mc9s08jm60??

0 Kudos

1,902 Views
kef
Specialist I
Sorry for bad advice, of course you are right. 
You could use jump table instead of vector table. You may hate it because of odd table entry size, but it could be faster and no push-push-rts would be needed to keep H register not touched.
 
 
( that's what I was thinking about :
 
void BootloadMain(void) {asm("JMP  0xF9FD");}
void Bootload_ISR_01(void) {asm("JMP  0xF9FA");}
void Bootload_ISR_01(void) {asm("JMP  0xF9F7");}
...
 
 
And in loadable app you would have something like this
 
typedef struct{
   char jmpopcode;
   void (*_vect)(void);
}psvct;

const psvct vectors[] @0xF9EB =
{   // Interrupt vector table
        {0xCC,UNASSIGNED_ISR},          /* ADC */
        {0xCC,UNASSIGNED_ISR},          /* KBD */
        {0xCC,UNASSIGNED_ISR},          /* TOF */
        {0xCC,UNASSIGNED_ISR},          /* TC1 */
        {0xCC,UNASSIGNED_ISR},          /* TC0 */
        {0xCC,UNASSIGNED_ISR},          /* IRQ */
        {0xCC,_Startup},                /* RESET */
};
 
)
 
 
0 Kudos