// Renode-only helper peripheral placed in reserved address space.
// The error is logged with an unimplemented function's name if a valid
// LR value is written to the peripheral's address.
bootrom_logger: Miscellaneous.AmbiqApollo4_BootromLogger @ sysbus 0x07FFFFFC
    bootromBaseAddress: 0x08000000

bootrom: Memory.MappedMemory @ sysbus 0x08000000
    size: 0x1000
    init:
        // Bootrom in Ambiq Apollo4b contains functions which are used by SDK.
        // Since the actual bootrom code isn't currently available even as a blob,
        // these simple implementations for necessary functions are provided:
        // * program_main2
        WriteWord 0x6C 0x2900  // asm: cmp r1, #0    // compare arg1
        WriteWord 0x6E 0xD000  // asm: beq 0x72      // jump to 0x72 if equal
        WriteWord 0x70 0xE0D6  // asm: b   0x220     // jump to 0x220
        WriteWord 0x72 0xE0C5  // asm: b   0x200     // jump to 0x200
        // * read_word
        WriteWord 0x74 0x6800  // asm: ldr r0, [r0, #0]
        WriteWord 0x76 0x4770  // asm: bx lr
        // * delay -- called with a number of iterations in 'r0' (see 'am_hal_delay_us' in
        //              SDK's 'mcu/apollo4p/hal/mcu/am_hal_utils.c'). 15 iterations are added
        //              because in hardware equivalent time is spent on checking burst mode
        //              and adjusting to it. It's safe to do so -- with AmbiqSuite v4.2 the
        //              number of iterations passed will always be lower than '2^32 - 1 - 15'.
        WriteWord 0x9C 0x300F  // asm: adds r0, #15  // add 15 iterations
        WriteWord 0x9E 0x3801  // asm: subs r0, #1   // decrement number of iterations
        WriteWord 0xA0 0x2800  // asm: cmp  r0, #0   // compare with 0
        WriteWord 0xA2 0xd1fc  // asm: bne.n 0x9E    // jump to 0x9E if not equal
        WriteWord 0xA4 0x4770  // asm: bx lr         // return
        // A handler which prevents silent usage of unimplemented functions:
        // 1. the address of the caller (LR) is written to the 'bootrom_logger'
        //    (see above) which logs an error with the name of the function,
        // 2. the jump to the 'logger_address' is performed, which aborts the
        //    simulation because it isn't a MappedMemory.
        WriteDoubleWord 0x30 0x3014f8df  // asm: ldr r3, logger_address
        WriteDoubleWord 0x34 0xe000f8c3  // asm: str lr, [r3]
        WriteWord 0x38 0x4718            // asm: bx r3
        WriteDoubleWord 0x48 0x07fffffc  // logger_address
        // Unimplemented functions jump to the handler (asm: bl handler).
        WriteDoubleWord 0x4C 0xfff0f7ff  // mass_erase
        WriteDoubleWord 0x50 0xffeef7ff  // page_erase
        WriteDoubleWord 0x54 0xffecf7ff  // program_main
        WriteDoubleWord 0x58 0xffeaf7ff  // program_info_area
        WriteDoubleWord 0x78 0xffdaf7ff  // write
        WriteDoubleWord 0x80 0xffd6f7ff  // info_erase
        WriteDoubleWord 0x98 0xffcaf7ff  // recovery
        // * program_main2 -- with parm1 == 0, assuming that numWords is not 0
        WriteWord 0x200 0x9800  // asm: ldr  r0, [sp]      // load numWords from stack
        WriteWord 0x202 0x0080  // asm: lsl  r0, r0, #2    // multiply numWords by 4 (to get number of bytes)
        WriteWord 0x204 0x009B  // asm: lsl  r3, r3, #2    // multiply dst to get the actual address
        WriteWord 0x206 0x501A  // asm: str  r2, [r3, r0]  // store r2 to dst + numWords
        WriteWord 0x208 0x3804  // asm: subs r0, #4        // decrease numWords
        WriteWord 0x20A 0x2800  // asm: cmp  r0, #0        // compare numWords with 0
        WriteWord 0x20C 0xDAFB  // asm: bge  0x206         // jump to 0x206 if not negative
        WriteWord 0x20E 0x2000  // asm: movs r0, #0        // set return value to OK
        WriteWord 0x210 0x4770  // asm: bx lr              // return
        // * program_main2 -- with parm1 == 1, assuming that numWords is not 0
        WriteWord 0x220 0x9800  // asm: ldr  r0, [sp]      // load numWords from stack
        WriteWord 0x222 0x0080  // asm: lsl  r0, r0, #2    // multiply numWords by 4 (to get number of bytes)
        WriteWord 0x224 0x009B  // asm: lsl  r3, r3, #2    // multiply dst to get the actual address
        WriteWord 0x226 0x5811  // asm: ldr  r1, [r2, r0]  // load src + numWords to r1
        WriteWord 0x228 0x5019  // asm: str  r1, [r3, r0]  // store r1 to dst + numWords
        WriteWord 0x22A 0x3804  // asm: subs r0, #4        // decrease numWords
        WriteWord 0x22C 0x2800  // asm: cmp  r0, #0        // compare numWords with 0
        WriteWord 0x22E 0xDAFA  // asm: bge  0x226         // jump to 0x226 if not negative
        WriteWord 0x230 0x2000  // asm: movs r0, #0        // set return value to OK
        WriteWord 0x232 0x4770  // asm: bx lr              // return

sysbus:
    init add:
        Tag <0x48000054,0x48000054> "DAXI_CONTROL" 0x4  // DAXIREADY set.
        Tag <0x40021004,0x40021008> "DEVPWREN" 0xFFFFFFFF // All devices powered up.
        Tag <0x40021018 4> "MEMEN" 0xFFFFFFFF
