// ACM "Automat" Edition :)
// Based on MCU: STM32L151CB or STM32L151CB-A

// STM32L151CB, ROM 128K, RAM 16K:
// Flash Memory Begins from 0x08000000
// Flash Memory Ends at 0x0801FFFF
// RAM Memory begins from 0x20000000
// RAM Memory ends at 0x20003FFF

// STM32L151CB-A, ROM 128K, RAM 32K:
// Flash Memory Begins from 0x08000000
// Flash Memory Ends at 0x0801FFFF
// RAM Memory begins from 0x20000000
// RAM Memory ends at 0x20007FFF

// Relative addresses of ROM:
// Base address: 0x08000000
//
// Static firmware: Bootloader program + Vector table + Priveleged section
// Bootloader fw. total: 32KiB - 256 priveleged bytes - 256 intvec bytes
// 0x00000         0x00100                             0x07F00          0x07FFF
// |                 |                                  |                     | 
// +-----------------+----------------------------------+---------------------+
// |   Interrupt     |        Bootloader program        |     Priveleged      |  
// |     Table       |                                  |      section        |  
// |   Bootloader    |            32,256 bytes          |     256 bytes       |  
// |    .intvec      |                                  |                     |  
// +-----------------+----------------------------------+---------------------+
// |<- sizeIntVect ->|<--------- sizeBootloader ------->|<-  sizePriveleged ->|
// |                                                                          |
// |<------------------------- sizeFixedFirmware ---------------------------->|

// Dynamic firmware: Application program + Vector table + Progversion section
// Application total: 96KiB - 256 program version bytes - 256 intvec bytes
// 0x80000          0x81000                            0x1FF00          0x1FFFF
// |                 |                                  |                     | 
// +-----------------+----------------------------------+---------------------+
// |   Interrupt     |            Application           |      Program        |
// |     Table       |              program             |      version        |
// |   Application   |                                  |      section        |
// |    .intvec      |            97,792 bytes          |    .progversion *   |
// +-----------------+----------------------------------+---------------------+
// |<- sizeIntVect ->|<--------- sizeApplication ------>|<- sizeProgversion ->|
// |                                                                          |
// |<-------------------------- sizeDynamicFirmware ------------------------->|
//
// *Note: Program version section includes CRC32 (4 bytes) section for checksum.
//
// 
// Relative addresses of RAM:
// Base address: 0x20000000
// RAM (Application), STM32L151CB and STM32L151CB-A
//
// Bootloader:
// 0x00000      0x00C00      0x00C10                                   0x03FFF    
// |               |            |                                          |
// +---------------+------------+------------------------------------------+
// |               |  Service   |                                          |
// |     CSTACK    |  BOOTSIGN  |               Common RAM                 |
// |      3KiB     |  section   |                                          |
// |               | .bootsign  |               13,296 bytes               |
// +---------------+------------+------------------------------------------+
// |<- sizeStack ->|<- ****** ->|<------------- sizeCommonRam ------------>|
//                    /      \
//                 sizeRamBootsign    

// Application:
// 0x00000      0x00C00      0x00C10        0x01C10                     0x03FFF    
// |               |            |              |                           |
// +---------------+------------+--------------+---------------------------+
// |               |  Service   |              |                           |
// |     CSTACK    |  BOOTSIGN  |     HEAP     |       Common RAM          |
// |      3KiB     |  section   |    .heap     |                           |
// |               | .bootsign  |     4KiB     |        9,200 bytes        |
// +---------------+------------+--------------+---------------------------+
// |<- sizeStack ->|<- ****** ->|<- sizeHeap ->|<----- sizeCommonRam ----->|
//                    /      \
//                 sizeRamBootsign     

// Relative addresses of RAM:
// Base address: 0x20000000
// RAM (Application), STM32L151CB-A only
//
// Bootloader and Application:
// 0x04000                                                            0x07FFF
// |                                                                   |
// +-------------------------------------------------------------------+
// |                                                                   |
// |                              Common RAM                           |
// |                                                                   |
// |                                16 KiB                             |
// +-------------------------------------------------------------------+
// |<------------------------- +++sizeCommonRam ---------------------->|

// BOOTSIGN - service region of RAM dedicated for storing the application/bootloader flags
// Common - general purpose application RAM region
// HEAP - application dynamic memory region (Application only)
// CSTACK - main thread stack

// ======================== Symbols and Sizes =================================

// Check for wheither symbol 'BOOTLOADER' is defined
if(!isdefinedsymbol(BOOTLOADER))
{
   // this is app, BOOTLOADER is not defined
   define symbol BOOTLOADER = 0; 
}

if( !isdefinedsymbol(STM32L151CBA) )
{
    define symbol STM32L151CBA = 0;
}

// Check for wheither symbol 'APPIMGINBOOT' is defined
if(!isdefinedsymbol(APPIMGINBOOT))
{   
   // by default, APPIMGINBOOT = 0, that means
   // no application image is placed in bootloader project
   define symbol APPIMGINBOOT = 0; 
}

// Define memory size:
define memory mem with size = 4G;

// Base hard-addresses:
define symbol baseROM                   = 0x08000000;           // @baseROM: Chip-ROM
define symbol baseRAM                   = 0x20000000;           // @baseRAM: Chip-RAM

// Region sizes:
define symbol sizeChipRom               = 0x20000;              // @sizeChipRom: Whole Chip-ROM size
define symbol sizeFixedFirmware         = 0x04000;              // @sizeFixedFirmware: Fixed Firmware Size, aka "Bootloader" + some constant data
                                                                // @sizeDynamicFirmware: Size of re-writable firmware and data
define symbol sizeDynamicFirmware       = sizeChipRom - sizeFixedFirmware;

define symbol sizeIntVect               = 0x00100;              // @sizeIntVect: size of interrupt vector table

if( STM32L151CBA )
{
    // Region sizes:
    define symbol sizeChipRam           = 0x08000;              // @sizeChipRam: Whole Chip-RAM size, 32KiB for STM32L151CBA
}
else
{
    // Region sizes:
    define symbol sizeChipRam           = 0x04000;              // @sizeChipRam: Whole Chip-RAM size, 16KiB for STM32L151CB
}

// ----------------------------------------------------------------------------------------------------
define exported symbol sizeRamBootsign  = 0x00010;              // @sizeRamBootsign: size of service RAM-region (app-->boot flags)
define exported symbol sizePriveleged   = 0x00100;              // @sizePriveleged: Priveleged section: contains constant device data
define exported symbol sizeProgversion  = 0x00100;              // @sizeProgversion: Program Version Sector size
define exported symbol sizeProgverCRC   = 0x00004;              // @sizeProgverCRC: Program Version Checksumm size

// @sizeProgverData: Program Version Data size
define exported symbol sizeProgverData  = sizeProgversion - sizeProgverCRC;              

// @sizeBootloader: Bootloader program ROM size
define exported symbol sizeBootloader   = sizeFixedFirmware -  sizePriveleged;

// @sizeApplication: Application program ROM size
define exported symbol sizeApplication  = sizeDynamicFirmware - sizeProgversion;

if( BOOTLOADER )
{
    // For Bootloader:
    define symbol sizeStack             = 0x01000;              // @sizeStack: CStack size (RAM)
    define symbol sizeHeap              = 0x00000;              // @sizeHeap: Heap size (RAM) - NO HEAP in bootloader
    define symbol sizeUsbBuffRam        = 0x01000;              // @sizeUsbBuffRam: logical sector for USB-Buffers
}
else
{
    // For Application:
    define symbol sizeStack             = 0x01000;              // @sizeStack: CStack size (RAM)
    define symbol sizeHeap              = 0x01000;              // @sizeHeap: Heap size (RAM)
    define symbol sizeUsbBuffRam        = 0x01000;              // @sizeUsbBuffRam: logical sector for USB-Buffers                                                                
}


// @sizeCommonRam: common readwrite memory
// The readwrite memory is reserved for CSTACK (@sizeStack), 
//  Service RAM-region (@sizeRamBootsign) and HEAP(@sizeHeap).
// The rest part of the chip RAM is common readwrite memory.
define symbol sizeCommonRam  = sizeChipRam - sizeRamBootsign - sizeStack - sizeHeap;

// Predefined IAR-symbol '__ICFEDIT_size_cstack__' must be defined:
define symbol __ICFEDIT_size_cstack__ = sizeStack;
// Predefined IAR-symbol '__ICFEDIT_size_heap__' must be defined:
define symbol __ICFEDIT_size_heap__   = sizeHeap;

// Absolute ranges (Region edjes): 
// 1) Fixed Firmware Region: 
// begins since the start of ROM and takes @sizeFixedFirmware bytes:
define symbol addrFixedFirmware    = baseROM; 
define symbol addrFixedFirmwareEnd = baseROM + sizeFixedFirmware - 1; 
// 1.1) Bootloader's Interrupt Vector Table:
// table begins at @addrFixedFirmware and takes @sizeIntVect bytes:
define exported symbol addrIntVectBoot    = addrFixedFirmware;
// Note: 'addrIntVectBoot' is referred by bootloader program
define symbol addrIntVectBootEnd = addrIntVectBoot + sizeIntVect - 1;    
// 1.2) Bootloader's program:
// follows the bootloader's interrupt vector table and takes @sizeBootloader:
define symbol addrBootloader    = addrIntVectBootEnd + 1;
define symbol addrBootloaderEnd = addrBootloader + sizeBootloader - 1;
// 1.3) Priveleged section:
// the end of the fixed firmware region:
define exported symbol addrPriveleged = addrFixedFirmwareEnd - sizePriveleged + 1;
define symbol addrPrivelegedEnd       = addrFixedFirmwareEnd;
// 2) Dynamic firmware:
// follows the fixed one - the rest part of the chip's ROM
define symbol addrDynamicFirmware    = addrFixedFirmwareEnd + 1;   
define symbol addrDynamicFirmwareEnd = addrDynamicFirmware + sizeDynamicFirmware - 1;
// 2.1) Application's Interrupt Vector Table:
// table begins at @addrDynamicFirmware and takes @sizeIntVect bytes:
define exported symbol addrIntVectApp = addrDynamicFirmware;
// Note: 'addrIntVectApp' is referred by bootloader program
define symbol addrIntVectAppEnd = addrIntVectApp + sizeIntVect - 1;    
// 2.2) Application program:
// follows the application's interrupt vector table and takes @sizeApplication:
define symbol addrApplication    = addrIntVectAppEnd + 1;   
define symbol addrApplicationEnd = addrApplication + sizeApplication - 1;
// 2.3) Program Version Sector:
// located in the tail of the dynamic firmware sector:
define symbol addrProgversion    = addrDynamicFirmwareEnd - sizeProgversion + 1;
define symbol addrProgversionEnd = addrDynamicFirmwareEnd; 
// 2.3.1) Program Version Sector Data region
// located at the beginning of the progversion section:
define symbol addrProgverData    = addrProgversion;  
define symbol addrProgverDataEnd = addrProgversionEnd - sizeProgverCRC;
// 2.3.2) Program Version Sector Checksumm region
// located at the end of the progversion section:
define symbol addrProgverCRC    = addrProgversionEnd - sizeProgverCRC + 1;  
define symbol addrProgverCRCEnd = addrProgversionEnd;

// Note: 'symChecksum' will be used by 'ielftool.exe' to reference start address of checksum section.
define exported symbol symChecksum =  addrProgverCRC;
// Note: 'symProgVers' is used by application to place the PROGVERSION structure using '@'
define exported symbol symProgVers =  addrProgversion;

if( BOOTLOADER )
{
    // Interrupt Vector Table: global definition for bootloader
    define exported symbol addrIntVect = addrIntVectBoot;
    define symbol addrIntVectEnd = addrIntVectBootEnd; 
    define symbol addrProgram    = addrBootloader;
    define symbol addrProgramEnd = addrBootloaderEnd;
}
else
{
    // Interrupt Vector Table: global definition for application
    define exported symbol addrIntVect = addrIntVectApp;
    define symbol addrIntVectEnd = addrIntVectAppEnd; 
    define symbol addrProgram    = addrApplication;
    define symbol addrProgramEnd = addrApplicationEnd;
}

// CSTACK RAM-region:
// Takes the first @sizeStack bytes from @baseRAM.
// If overflows, it does not damage any other data.
define symbol addrStackStart    = baseRAM;
define symbol addrStackEnd      = addrStackStart + sizeStack - 1;
// Service RAM-region:
// Follows the CSTACK RAM-region and takes @sizeRamBootsign bytes
define symbol addrSvcRamStart   = addrStackEnd + 1;
define symbol addrSvcRamEnd     = addrSvcRamStart + sizeRamBootsign - 1;
// Heap RAM-region:
// Follows the Service RAM-region and takes @sizeHeap bytes
define symbol addrHeapStart     = addrSvcRamEnd + 1;
define symbol addrHeapEnd       = addrHeapStart + sizeHeap - 1;
// Common RAM-region:
// Follows the Heap RAM-region and takes @sizeCommonRam bytes
define symbol addrRamStart      = addrHeapEnd + 1;
define symbol addrRamEnd        = addrRamStart + sizeCommonRam - 1;

// ============================= REGIONS ======================================

// ------------------------------------------------------------------------------
// Bootloader/Application Interrupt Vector Table (current project):
define region regionIntVec = mem:[ from addrIntVect to addrIntVectEnd ];

// Bootloader/Application program region (current project execution ROM):
define region regionReadonly = mem:[ from addrProgram to addrProgramEnd ];
// ------------------------------------------------------------------------------

// Service RAM region:
define region regionSvcRAM     = mem:[ from addrSvcRamStart to addrSvcRamEnd ];

// Common RAM region:
define region regionRAM        = mem:[ from addrRamStart to addrRamEnd ];

if( sizeHeap > 0)
{
    // HEAP RAM region:
    define region regionHeap   = mem:[ from addrHeapStart to addrHeapEnd ];
}

// CSTACK RAM region:
define region regionStack      = mem:[ from addrStackStart to addrStackEnd ];

// Program Version ROM-region (data only, no checksum):
define region regionProgversion = mem:[ from addrProgverData to addrProgverDataEnd ];

// Program Version Checksumm ROM-region (only checksum):
define region regionProgverCRC = mem:[ from addrProgverCRC   to addrProgverCRCEnd ];

if( !BOOTLOADER )
{
   // Bootloader-image region
   define region regionBootImg = mem:[ from addrFixedFirmware to addrFixedFirmwareEnd ];
}
else
{
   // Application-image region
   define region regionAppImg = mem:[ from addrDynamicFirmware to addrDynamicFirmwareEnd ];
}

// =============================  BLOCKS  ======================================
// Defining blocks:

// Main stack:
define block CSTACK      with alignment = 8,  size = sizeStack        { section .cstack  };

if( sizeHeap > 0 )
{
    // Dynamic memory (Heap):
    define block HEAP    with alignment = 8,  size = sizeHeap         { };
}

// Bootloader signature (App-->Boot data exchange)
define block BOOTSIGN    with alignment = 8,  size = sizeRamBootsign  { readwrite data section .bootsign };

// USB-Buffers (logical block)
define block USBBUF      with alignment = 8,  size = sizeUsbBuffRam   { section .usbbuf     };

if( !BOOTLOADER )
{
    // For Application:
    
    // Bootloader-image block: contains full fixed firmware image
    define block BOOTIMG with alignment = 4,  size = sizeFixedFirmware { readonly data section .bootimg };
   
    // Application program version sector
    define block PROGVERSION with alignment = 4,  size = sizeProgverData  { section .progver    };
    define block PROGVERCRC  with alignment = 4,  size = sizeProgverCRC   { section .progvercrc };
}
else
{   
    // For Bootloader:
    
    if( APPIMGINBOOT )
    {
        // Application-image block: contains full dynamic firmware image
        define block APPIMG with alignment = 4,  size = sizeDynamicFirmware { section .appimg };
    }
}

// =========================  Initializers  ====================================

// Initializers:
initialize by copy { readwrite           };

do not initialize  { section .noinit     };
do not initialize  { section .bootsign   };

// ===========================  Placement  =====================================
// Current project Interrupt Vector Table:
place in regionIntVec        { readonly section .intvec };

// Current project executable readonly memory:
place in regionReadonly      { readonly };

// Current project common readwrite memory (non-marked + marked):
place in regionRAM           { readwrite, section .flashram, section .grombuf, last block USBBUF };

// Service RAM-region: BOOTSIGN block
place in regionSvcRAM        { first block BOOTSIGN };

if( sizeHeap > 0 )
{
    // Heap RAM-region
    place in regionHeap      { first block HEAP };
}

// CSTACK region:
place in regionStack         { first block CSTACK };

if( !BOOTLOADER )
{
    // For Application:
    place in regionBootImg      { first block BOOTIMG     };
    place in regionProgversion  { first block PROGVERSION };
    place in regionProgverCRC   { first block PROGVERCRC  };
    
    keep { section .bootimg, block BOOTIMG , section .progver, section .progvercrc };
}
else
{
    // For Bootloader:
    if( APPIMGINBOOT )
    {
        place in regionAppImg   { first block APPIMG };
        keep { section .appimg };
    }  
}

keep { section .intvec, section .bootsign, block BOOTSIGN };