Cortex M0+ compile flow

---------------
Cortex M0-plus (CM0+):
---------------
Here, we use only minimal required C code files from ARM.
steps:
1. make: make 32 bit bin file from c code: only these files needed:
   *.c: test1.c, main.c, boot.c, IRQService.c, export.s
   *.h: address_def.h, defines.h
   *.txt: scatter.txt
2. In irun, load this bin file in rom memory, and start sim

make:
---
make -f /db/.../Makefile all

Makefile:
-------
CCFLAGS = --cpu=Cortex-M0 -c --asm --interleave --apcs=interwork -Otime -D RAM_ABSOLUTE_BASE_ADDR -D main=__main -g
LDFLAGS = --cpu=Cortex-M0 --map --no_debug --datacompressor=off --map --symbols --info=inline
IKDEPS = /sim/.../Makefile

all: clear test1_32.dat clean

############ rm files at start
clear:
      rm -rf *.o *.sym *.list *.bin *.elf *.sec *.dis *.map *.ihex *.obj *.log *.inc *.dat

###########start compilation .dat<=.ihex<=.elf<=.o<=.c
test1_32.dat : test1.ihex
        @echo " *** building $@ ***" => building test1_32.dat
        ihex2dat32 -input $< -output $@ => o/p in 32 bit mem mage file

test1.ihex : test1.elf
        fromelf --i32 $< --output $@

test1.elf : boot.o IRQService.o init.o export.o test1.o
        armlink -o $@  boot.o IRQService.o init.o export.o test1.o $(LDFLAGS) --scatter scatter.txt

test1.o: test1.c $(IKDEPS)
       armcc $(CCFLAGS) -c -o $@ $<

#get .o files for boot.c, IRQService.c, init.c, export.s
boot.o: boot.c $(IKDEPS) => similarly for IRQService.c, init.c
      armcc $(CCFLAGS) -c -o $@ $<
IRQService.o: ...
init.o: ....
export.o: export.s $(IKDEPS) => export.c isn't there, use export.s
      armasm --cpu=Cortex-M0 --keep -o $@ $<


##### remove files at end
clean:
        rm -rf *.obj

------------------------
output of running this:
#clean
rm -rf *.o *.sym *.list *.bin *.elf *.sec *.dis *.map *.ihex *.obj *.log *.inc *.dat

#compile files
armcc --cpu=Cortex-M0 -c --asm --interleave --apcs=interwork -Otime  -D RAM_ABSOLUTE_BASE_ADDR -D main=__main -g -c -o boot.o /sim/.../boot.c
armcc ... IRQService.c
armcc ... init.c
armasm --cpu=Cortex-M0 --keep -o export.o /sim/.../export.s
armcc ... test1.c

armlink -o test1.elf boot.o IRQService.o export.o init.o basic.o --cpu=Cortex-M0 --map --no_debug --datacompressor=off --map --symbols --info=inline --scatter /sim/.../scatter.txt => Here armlink is using --scatter which causes it to use scatter.txt for ro-base, rw-base, zi-base. For sporsho, we used --ro-base and --rw-base on armlink cmdline instead of using scatter file.  

#show inline results => symbol table, memory map,
Image Symbol Table ....
Memory Map of the image ....

#generate .elf and .dat
fromelf --i32 test1.elf --output test1.ihex
ihex2dat32 -input test1.ihex -output test1_32.dat => final *.dat file generated

#clean
rm -rf *.obj

-------------------------------------------
#contents of various files

###### boot.c ######
typedef void (*intr_handler)(void);
extern void IRQService (void); // Default interrupt handler
void BaseIRQService0 (void); //similarly for IRQ0 to IRQ31
intr_handler IRQService0   = IRQService;

//define func for all intr handlers, either as C/asm code or via calling other func.
void Reset_Handler (void) {
        init (); //this calls init func, defined in init.c
}

void BaseIRQService0 (void) { //irq0.
    IRQService0 (); //this ultimately calls IRQService
}

typedef const int * vect_t; //vect_t is a ptr to type "const int"
const int * __Vectors[] __attribute__ ((section("vectors"))) = { //this matches contents of .dat binary file below
        (vect_t) (&USR_STACK),     //addr=0x0000, stores MSP value, here it stores 0x20046F00
        (vect_t) Reset_Handler,    //addr=0x0004
        (vect_t) NMI_Handler,       //addr=0x0008
        (vect_t) HardFault_Handler,//addr=0x000C
        (vect_t) 0xFFFFFFFC,       //addr=0x0010    
        (vect_t) 0xFFFFFFFC,       //addr=0x0014
        (vect_t) 0xFFFFFFFC,       //addr=0x0018
        (vect_t) 0xFFFFFFFC,       //addr=0x001C
        (vect_t) 0xFFFFFFFC,       //addr=0x0020
        (vect_t) 0xFFFFFFFC,       //addr=0x0024
        (vect_t) 0xFFFFFFFC,       //addr=0x0028
        (vect_t) SVC_Handler,       //addr=0x002C, stores addr of SVC intr handler, which in this case is 0x00000115
        (vect_t) 0xFFFFFFFC,       //addr=0x0030
        (vect_t) 0xFFFFFFFC,       //addr=0x0034
        (vect_t) PendSV_Handler,   //addr=0x0038, stores addr of Pend intr handler, which in this case is 0x00000127
        (vect_t) SysTick_Handler,  //addr=0x003C, stores addr of systick intr handler, which in this case is 0x00000139
        (vect_t) BaseIRQService0,  // similarly for IRQ0 to IRQ31, addr=0x0040 to 0x00BC (addr 0x00C0 is the first addr where this vector table ends). stores addr starting from 0x00000141 to 0x000001FB, each IRQ is 6 bytes.
       //(vect_t) IRQService,      //we could directly point to IRQService routine. That's what we used for compiled code below
}

asm code for boot
----------
AREA ||.text||, CODE, READONLY, ALIGN=2 => this is text section

Reset_Handler PROC
000000  b510              PUSH     {r4,lr}
000002  f7fffffe          BL       init => jumps to init, here target addr is not yet finalized, so we see jump inst as f7ff_fffe. Once init addr is know in final linking of *.o files, this BL changes coding to f827_f000 (as seen in *.dat file below) which implies target_msb[10:0]=000, target_lsb[10:0]=027<<1 => pc=pc+(027<<1)=0c6+04e=0x114 (init section starts from 0x114, so it's correct). (LR stored with next PC=06=0xc6, so return from main() comes right here)
000006  bd10              POP      {r4,pc}
ENDP

similarly for other proc handlers
NMI_Handler PROC
000008  4805              LDR      r0,|L1.32| => Load pc+|L1.32| into r0 reg. (4805=>reg=r0,label=05<<2=0x14(dec=20),pc+0x14=0x0a+0x14=0x1e. Note that label=0x05 is resolved here itself, since the label is within this file, so compiler knows how much to add to goto that label.
00000a  6800              LDR      r0,[r0,#0]  ; NMIService, r0=
00000c  4700              BX       r0 => pc=r0=
ENDP

HardFault_Handler PROC
|L1.14|
00000e  bf00              NOP
000010  e7fd              B        |L1.14| => while (1) { __nop (); e7fd => offset=0x7fd=-3, so pc=pc-3=0x012-0x003=0x00e (prev inst)
ENDP

SVC_Handler PROC
|L1.18|
000012  bf00              NOP
000014  e7fd              B        |L1.18| => while (1) { __nop ();
ENDP

PendSV_Handler PROC
|L1.22|
000016  bf00              NOP
000018  e7fd              B        |L1.22|
ENDP

SysTick_Handler PROC
|L1.26|
00001a  bf00              NOP
00001c  e7fd              B        |L1.26|
ENDP

00001e  0000              DCW      0x0000
|L1.32| => NMIService is here
                          DCD      ||.data||
##data section for boot.c starts from here
                          AREA ||.data||, DATA, ALIGN=2 => area named .data
                  NMIService
                          DCD      IRQService
                          AREA ||area_number.5||, DATA, ALIGN=2 => area named .area_number.5
                          EXPORTAS ||area_number.5||, ||.data||
                  IRQService0
                          DCD      IRQService
                         AREA vectors, DATA, ALIGN=2 => area named vectors
                  __Vectors
                          DCD      0x20046f00
                          DCD      Reset_Handler
                          DCD      NMI_Handler
                          DCD      HardFault_Handler
                          DCD      0xfffffffc
                          DCD      0xfffffffc
                          DCD      0xfffffffc
                          DCD      0xfffffffc
                          DCD      0xfffffffc
                          DCD      0xfffffffc
                          DCD      0xfffffffc
                          DCD      SVC_Handler
                          DCD      0xfffffffc
                          DCD      0xfffffffc
                          DCD      PendSV_Handler
                          DCD      SysTick_Handler
                          DCD      IRQService
                ....
                          DCD      IRQService (32 of these)

---------------

######## init.c ###########
void init (void) {
 main(); //this calls "main" func in user code, defined in test1.c
}

asm code for init:
----------
AREA ||.text||, CODE, READONLY, ALIGN=1
init PROC

000000  b510              PUSH     {r4,lr}
000002  f7fffffe          BL       __main => BL is 32 bit inst (LR stored with next PC=06=0x11a, so return from main() comes right here)
000006  bd10              POP      {r4,pc}

ENDP
----------

######## IRQService.c ###########
void IRQService (void) { //default IRQ, doesn't do anything
 (*(volatile uint32 *)(TB_RSVD_ADDR + 0x0F98))++; //FAIL_LOC++
 (*(volatile uint32 *)(TB_RSVD_ADDR + 0x0FEC)) = 0xD0D0D0D0; //DISPLAY(0xD0D0D0D0)
 (*(volatile uint32 *)(TB_RSVD_ADDR + 0x0F90)) = 0xB000B000; //FAIL;   //writes to some reserved mem section to indicate to verilog tb that it's in IRQ
 (*(volatile uint32 *)(TB_RSVD_ADDR + 0x0FAC)) = 0x50; __nop(); (*(volatile uint32 *)(TB_RSVD_ADDR + 0x0FAC)) = 0x11; //EXIT; wrt to BOOTCODE_ADDR
 return; //just returns back
}

asm code:
-------
000000  4807              LDR      r0,|L1.32|
000002  6981              LDR      r1,[r0,#0x18] => FAIL_LOC++;
000004  1c49              ADDS     r1,r1,#1
000006  6181              STR      r1,[r0,#0x18]
000008  4a07              LDR      r2,|L1.40| => DISPLAY(0xD0D0D0D0);
00000a  4906              LDR      r1,|L1.36|
00000c  62d1              STR      r1,[r2,#0x2c]
00000e  4907              LDR      r1,|L1.44| => FAIL
000010  6101              STR      r1,[r0,#0x10]
000012  2150              MOVS     r1,#0x50 => EXIT
000014  62c1              STR      r1,[r0,#0x2c]
000016  bf00              NOP
000018  2111              MOVS     r1,#0x11
00001a  62c1              STR      r1,[r0,#0x2c]
00001c  4770              BX       lr => return
00001e  0000              DCW      0x0000
                  |L1.32|
                          DCD      0x20046f80
                  |L1.36|
                          DCD      0xd0d0d0d0
                  |L1.40|
                          DCD      0x20046fc0
                  |L1.44|
                          DCD      0xb000b000
------

######## test1.c ###########
int main (void) {
  int i=0;
    while(i<1) i=i+1;
    return(0);
}

asm code:
---------
000000  2000              MOVS     r0,#0 => r0=0
|L1.2|
000002  1c40              ADDS     r0,r0,#1 => while(i<1) i=i+1;
000004  2801              CMP      r0,#1
000006  dbfc              BLT      |L1.2|
000008  2000              MOVS     r0,#0 => return(0)
00000a  4770              BX       lr
ENDP
-----------


######## export.s ###########
  IMPORT ||Image$$ROM_EXEC2$$RO$$Limit||  => ROM_EXEC2 region (in scatter.txt below)
  IMPORT ||Image$$RAM_EXEC1$$RW$$Base||   => RAM_EXEC1 region
  IMPORT ||Image$$RAM_EXEC1$$RW$$Length||
  IMPORT ||Image$$RAM_EXEC2$$ZI$$Base||   => RAM_EXEC2 region
  IMPORT ||Image$$RAM_EXEC2$$ZI$$Length||
        END

######## scatter.txt #########
scatter file has 1 or more load region for diff obj *.o files. Each load region has RO and RW/ZI regions. The addr and placement of these regions is specified in

ROM_LOAD 0x0 {
    ROM_EXEC1 0x0 { => start from addr=0x0000
        boot.o (vectors, +First) => boot.c "vectors" sction is put here (RO)
        * (InRoot$$Sections)
    }
    ROM_EXEC2 0xc0 { => addr=0xC0 is where the vector section has ended. We put all other code starting here (RO)
        *.o
    }
    OTP_EXEC3 +0 {
        *.o (.sec_text)
    }
    RAM_EXEC1 0x00043000 { //let's say this has 148 bytes (=0x94 bytes)
      *.o (.data,.RW)
    }
    RAM_EXEC2 +0 { //then starting addr for this is 0x00043094
      *.o (.bss)
    }
}


#contents of .dat (32 bit):
Section 1 => ROM_EXEC1 (192 bytes)
---------
 @00  20046F00 000000C1 000000C9 000000CF => addr 0(msp) loaded with 2004_6f00. Reset=0xC0/NMI=0xC8/HardFault=0xCE
 @10  FFFFFFFC FFFFFFFC FFFFFFFC FFFFFFFC
 @20  FFFFFFFC FFFFFFFC FFFFFFFC 000000D3 => 0xD2=SVC handler
 @30  FFFFFFFC FFFFFFFC 000000D7 000000DB => 0xD6=PendSV, 0xDA=SysTick
 @40  000000E5 000000E5 000000E5 000000E5  => IRQ0-IRQ31 all goto same IRQService
 @50  000000E5 000000E5 000000E5 000000E5
 @60  000000E5 000000E5 000000E5 000000E5
 @70  000000E5 000000E5 000000E5 000000E5
 @80  000000E5 000000E5 000000E5 000000E5
 @90  000000E5 000000E5 000000E5 000000E5
 @a0  000000E5 000000E5 000000E5 000000E5
 @b0  000000E5 000000E5 000000E5 000000E5
--- All vector table ends before here ----

Section 2 => ROM_EXEC2 (104 bytes)
---------
 @c0  => boot.c starts here. reset handler starts, then NMI, HardFault, SVC, PendSV, SysTick  here
----
F000B510 => reset handler (B510 => PUSH {r4,lr})
BD10F827 => F827_F000 => BL init (target addr=000_027=>pc=pc+027=0xc6+(0x27<<1)=0x114, (BD10 => POP {r4,pc})
 @c8 => NMI handler
68004805 BF004700 (BF00 = NOP from HardFault handler)
 @d0 BF00E7FD BF00E7FD BF00E7FD 0000E7FD => HardFault, SVC, PendSV, SysTick (last 0000 is for next inst DCW 0x0000)
 @e0  00043000 => DCD ||.data|| => 0x0004_3000 is addr of RAM region

 @e4 => IRQservice.c starts here
---
69814807 61811C49 49064A07
 @f0  490762D1 21506101 BF0062C1 62C12111
@100  
00004770 => 4770=BX lr, 0000=DCW 0x0000
20046F80 D0D0D0D0 20046FC0 => all DCD
@110  
B000B000 => all DCD

@114 => init.c starts here
---
F000B510 =>
BD10F801 => F801_F000 => BL __main (target addr=000_001 =>PC=PC+1=

@11c => main.c starts here
---
1C402000 =>  main starts from here __main
DBFC2801
47702000 => end of main.c

@128
000000E5 000000E5 => extra bytes, not sure for what

--------------
seq of exec of code above:
1. HCLK starts running. 1 cycle later, HRESET_N gets released.
2. HADDR goes from 0x00->0x04->0xC0,0xC4(reset_handler)->0x114,0x118(init)->0x11c,0x120,0x124(main)->

----------------------------------------
Section 3: RAM_EXEC1
---------
remove below lines ---

4770BF30 => Reset_Handler starts here (B510 => PUSH {r4,lr})
4770B662
4770B672 4770BF00
 @d0  8F5FF3BF F3BF4770 47708F4F 8F6FF3BF
 @e0  00004770
F000B510 => Reset_Handler starts here (B510 => PUSH {r4,lr})
BD10F827 => F827_F000 => BL init, (BD10 => POP {r4,pc})
68004805
 @f0  BF004700 BF00E7FD BF00E7FD BF00E7FD
 @100  0000E7FD 00043000 69814807 61811C49
 @110  49064A07 490762D1 21506101 BF0062C1
 @120  62C12111 00004770 20046F80 D0D0D0D0
 @130  20046FC0 B000B000 F000B510 BD10F81D
 @140  F7FFB510 BD10FFC5 F7FFB510 BD10FFC4
 @150  F7FFB510 BD10FFC3 F7FFB510 BD10FFB7
 @160  F7FFB510 BD10FFAF F7FFB510 BD10FFAD
 @170  F7FFB510 BD10FFA5
 @12C
1C402000 => main starts from here __main
DBFC2801
47702000 => ENDP
 @138
000000E5 000000E5

-------------------------