////////////////////////////////////////////////////////////////////////
//
//  boot.c: pico2 booter (coff/elf version)
//      version 1.2 (May 6, 2010)
//
//  (c) Hideki Kozima (xkozima@myu.ac.jp), subject to GPLv2
//

#include "sh7046f.h"

//
//  __main: dummy function

void  __main (void) {}

////////////////////////////////////////////////////////////////////////
//
//  operators for interrupt control

//
//  set_vbr: set vector base register

void  set_vbr (void *vbr)
{
    asm(" ldc %0,vbr "::"r"(vbr));
}

//
//  get_vbr: get vector base register

uint  *get_vbr ()
{
    uint  *vbr;

    asm(" stc vbr,%0 ":"=r"(vbr):);
    return  vbr;
}

//
//  set_imask: enable interrupts
//      Call once right after having get interrupt handlers ready.

void  set_imask (ushort mask)
{
    uint  value;

    mask <<= 4;
    mask &= 0x00f0;
    asm(" stc sr,%0 ":"=r"(value):);
    value &= 0xffffff0f;
    value = value | mask;
    asm(" ldc %0,sr "::"r"(value));
}

//
//  definterrupt: associate interrupt and handler function
//      ex. definterrupt(173, (void *) SCI_receive_byte);
//          #pragma interrupt
//          void  SCI_receive_byte (void) {
//              ...
//          } 

void  definterrupt (ushort intno, void *handler(void))
{
    uint  *vbr;

    vbr = get_vbr();
    vbr += intno;
    *vbr = (uint) handler;
}

////////////////////////////////////////////////////////////////////////
//
//  boot: pico2 first initialization
//        (just in order to avoid hardware collision)

extern char  svbase;

void  boot (void)
{
    void  section_init(void);
    int   main(void);

    //  PortA initialization
    //      PA7-0: in (tentative)
    //      PA8: RxD, PA9: TxD, 
    //      PA10: out=0 (TE)
    //      PA15-11: in (tentative)
    PFC.PACRL1.WORD = 0x0005;
    PFC.PACRL2.WORD = 0x0000;
    PFC.PACRL3.WORD = 0x0300;
    PFC.PAIORL.WORD = 0x0400;
    PA.DR.WORD = 0x0000;                        //  TE off

    //  PortB initialization
    //      PB5-2: in (tentative)
    PFC.PBCR1.WORD = 0x0000;
    PFC.PBCR2.WORD = 0x0000;
    PFC.PBIOR.WORD = 0x0000;			//  PB2-5 in

    //  PortE initialization
    //      PE21-17: in  (SWs)
    //      PE16-12: out (LEDs)
    //      PE11-0 : out (with zero)
    PFC.PECRH.WORD  = 0x0000;
    PFC.PECRL1.WORD = 0x0000;
    PFC.PECRL2.WORD = 0x0000;
    PFC.PEIORH.WORD = 0x0001;
    PFC.PEIORL.WORD = 0xffff;
    PE.DRH.WORD = 0x0000;                       //  LED5   on
    PE.DRL.WORD = 0x0000;                       //  LED4-0 on

    //  initialize memory
    section_init();

    //  set VBR
    set_vbr(&svbase);

    //  start main program
    main();
}

//
//  memory initialization (cf. rom.x)
//      .text   [_stext, _etext)  for code
//      .rodata [ ...          )  for readonly data
//      initvar [_mdata, ...   )  for initvar for .data
//      .data   [_sdata, _edata)  for variables with init
//      .bss    [_sbss,  _ebss )  for variables without init
//  note: .data has to be copied from the end of .text area.

extern char  mdata, sdata, edata, sbss, ebss;

void  section_init (void)
{
    char  *src;
    char  *dst;

    //  initialize .data area
    //      initvar is located in [_mdata, ...), 
    //      so copy to .data = [_sdata, _edata)
    src = &mdata;
    dst = &sdata;
    while (dst < &edata)
        *dst++  = *src++;

    //  clear .bss area
    for ( dst = &sbss; dst < &ebss; dst++ )
        *dst = 0;
}

////////////////////////////////////////////////////////////////////////
