.struct 0       @ mcountdata
mcountdataSize:
    .struct mcountdataSize+4
statsEntrySize:
    .struct statsEntrySize+4
stackEntrySize:
    .struct stackEntrySize+4
mstackptr:
    .struct mstackptr+4
mstackbottom:
    .struct mstackbottom+4
moverflow:
    .struct moverflow+4
menabled:
    .struct menabled+4
mentrycountH:
    .struct mentrycountH+4
mentrycountL:
    .struct mentrycountL+4
mleaveproc:
    .struct mleaveproc+4
mhashtable:
    .struct mhashtable+4
mstattable:
    .struct mstattable+4
mstatentry:
    .struct mstatentry+4
mstatend:
    .struct mstatend+4
nentries:
    .struct nentries+4
ndepth:
    .struct ndepth+4
mtotalticks:
    .struct mtotalticks+4
mtotalclocks:
    .struct mtotalclocks+4
sizeof_mcountdata:

.struct 0       @ mstatdata
slink:
    .struct slink+4
scount:
    .struct scount+4
scaller:
    .struct scaller+4
sfunction:
    .struct sfunction+4
stimeH:
    .struct stimeH+4
stimeL:
    .struct stimeL+4
ssubcallsH:
    .struct ssubcallsH+4
ssubcallsL:
    .struct ssubcallsL+4
sizeof_mstatdata:

@.struct 0       @ mstackentry
@caller:
@    .struct caller+4
@ostimer:
@    .struct ostimer+4
@function:
@    .struct function+4
@entrycountH:
@    .struct entrycountH+4
@entrycountL:
@    .struct entrycountL+4
@sizeof_mstackentry:


ostimer = 0xa9000010

.extern _mcountdata

@
@========== called on function entry =================
@
@ stack layout:
@   fp-c = fp of caller
@   fp-8 = sp of caller
@   fp-4 = caller of function == IP
@   fp -> pc of stmfd instruction + 8
@
    .text
    .align 0
    .global mcount
mcount:
   stmfd  sp!, {r0-r5,r9,r10}
   ldr r9, =_mcountdata                 @ r9 = ptr to datastruct
   

   ldr r0, [fp, #-4]                    @ r0 = caller

   ldr r1, =ostimer                     @ r1 = time
   ldr r1, [r1]

   mov r2, lr                           @ r2= calledfunction

   ldr r4, [r9, #mentrycountL]          @ r4= subsL
   adds r4, r4, #1
   str r4, [r9, #mentrycountL]
   ldr r3, [r9, #mentrycountH]          @ r3= subsH
   adc r3, r3, #0
   str r3, [r9, #mentrycountH]

   ldr r10, [r9, #mstackptr]
   ldr r5, [r9, #mstackbottom]
   cmp r10, r5

   ldrlt r0, [r9, #moverflow]
   addlt r0, r0, #1
   strlt r0, [r9, #moverflow]
   blt mcountexit

   stmfd r10!, {r0-r4}                 @ caller, ostimer, function, entrycountH, entrycountL
   str r10, [r9, #mstackptr]
   
   ldr r1, [r9, #mleaveproc]           @ slip into return address
   str r1, [fp, #-4]

mcountexit:

   ldmfd sp!, {r0-r5,r9,r10}
   mov  pc,lr

@
@========== called on function exit =================
@
    .global mcountleave
mcountleave:
   stmfd  sp!, {r0-r10}
   ldr r9, =_mcountdata                 @ r9 = ptr to datastruct

   ldr r10, [r9, #mstackptr]
   ldmfd r10!, {r0-r4}                  @ caller, ostimer, function, entrycountH, entrycountL
   str r10, [r9, #mstackptr]

   ldr r10, =ostimer
   ldr r10, [r10]
   sub r1, r10, r1                      @ r1 = time spent in function, ignoring overflows

   ldr r10, [r9, #mentrycountL]
   subs r4, r10, r4                     @ r4= nr of subsL
   ldr r10, [r9, #mentrycountH]
   sbc r3, r10, r3                      @ r3= nr of subsL

   ldr r10, [r9, #mhashtable]

   eor r5, r2,r0
   eor r5, r5, r5, lsr #16

   mov r5, r5, lsl#16
   mov r5, r5, lsr#16
   bic r5, r5, #3                       @ r5 = hash index

   add r6, r10,r5                       @ r6 = current entry

nextentry:
   mov  r7, r6                      @ remember where we came from.

   ldr r6, [r6]
   teq r6, #0
   beq  newentry

   ldr r5, [r6, #sfunction]             @ check if this is the right entry
   teq r2, r5
   bne  nextentry

   ldr r5, [r6, #scaller]
   teq r0, r5
   bne  nextentry

@ this is 'the' entry!

   ldr r5, [r6, #stimeL]                @ add to time-spent
   adds r5, r5, r1
   str r5, [r6, #stimeL]
   ldr r5, [r6, #stimeH]
   adc r5, r5, #0
   str r5, [r6, #stimeH]

   ldr r5, [r6, #scount]                @ inc call count
   add r5, r5, #1
   str r5, [r6, #scount]
   
   ldr r5, [r6, #ssubcallsL]            @ add to subroutines called
   adds r5, r5, r4
   str r5, [r6, #ssubcallsL]
   ldr r5, [r6, #ssubcallsH]
   adc r5, r5, r3
   str r5, [r6, #ssubcallsH]

   b mexit

newentry:
   ldr r6, [r9, #mstatentry]
   add r6, r6, #sizeof_mstatdata
   str r6, [r9, #mstatentry]

   ldr r5, [r9, #mstatend]
   cmp r6, r5
   bgt mexit                        @ no more stats entries available!!

   str  r6, [r7]                    @ update link or hash entry.

   mov r5, #0
   str r0, [r6, #scaller]
   str r1, [r6, #stimeL]
   str r5, [r6, #stimeH]
   str r2, [r6, #sfunction]
   str r3, [r6, #ssubcallsH]
   str r4, [r6, #ssubcallsL]
   str r5, [r6, #slink]
   mov r5, #1
   str r5, [r6, #scount]

mexit:
   mov lr, r0
   ldmfd  sp!, {r0-r10}
   mov pc, lr

Xmcountdata:
    .word _mcountdata
Xostimer:
    .word  0xa9000010

