; Function profiling ARM code V2.13 17/2/08
; See jprof2.h for usage stuff
; Copyright 2008 Jeffrey Lee
; This file is part of WOUM.
; WOUM is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
; WOUM is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
; You should have received a copy of the GNU General Public License
; along with WOUM.  If not, see <http://www.gnu.org/licenses/>.

R0	RN	0
R1	RN	1
R2	RN	2
R3	RN	3
R4	RN	4
R5	RN	5
R6	RN	6
R7	RN	7
R8	RN	8
R9	RN	9
R10	RN	10
R11	RN	11
R12	RN	12
R13	RN	13
R14	RN	14
PC	RN	15

; Offsets in jprof2_struct
time_func_entered	EQU	8
time_total	EQU	12
count	EQU	16
func_r14	EQU	20

	AREA	jprof2, CODE, READONLY

	IMPORT	|Image$$RO$$Base|
	IMPORT	|Image$$RO$$Limit|

	EXPORT	jprof2_nextfunc
	EXPORT	jprof2_funcname
	EXPORT	jprof2_codeblock
	EXPORT	jprof2_codeblock_entry
	EXPORT	jprof2_codeblock_instr
	EXPORT	jprof2_codeblock_branch
	EXPORT	jprof2_codeblock_struct
	EXPORT	jprof2_codeblock_timeptr
	EXPORT	jprof2_codeblock_length

local_ro_base
	DCD |Image$$RO$$Base|

local_ro_limit
	DCD |Image$$RO$$Limit|

testinstr
	MOV R12,R13 ; First instruction must match this otherwise we probably can't profile the function

; assmbler helper functions for jprof2.c
jprof2_nextfunc ; In: R0=previous function, or 0
		;     R1=0 to search for all named functions, 1 for only profilable ones
		; Out: R0=next function, or 0
		; Returns a pointer to the next function which has a name
	CMP R0,#0
	LDREQ R0,local_ro_base
	LDR R2,local_ro_limit
	CMP R1,#0
	LDRNE R3,testinstr
	MOVEQ R3,#0
nextfunc_loop
	CMP R0,R2
	MOVGE R0,#0
	MOVGE PC,R14
	LDR R1,[R0],#4
	MOV R1,R1,LSR #8
	CMP R1,#&FF0000 ; 0xFF0000xx, so probably a function
	BNE nextfunc_loop
	LDR R1,[R0]
	CMP R3,#0 ; Check if function needs to be profilable
	CMPNE R1,R3
	BNE nextfunc_loop
	MOV PC,R14

jprof2_funcname ; In: R0=pointer to function
	; Out: R0=function name, or 0 for none
	SUB R0,R0,#4
	LDR R1,[R0]
	MOV R2,R1,LSR #8
	CMP R2,#&FF0000
	MOVNE R0,#0
	ANDEQ R1,R1,#255
	SUBEQ R0,R0,R1
	MOV PC,R14

theblock ; Code block to use as a template for profiling code
	DCB "jprof2profiler",0,0
	DCD &FF000010
entryp	STMDB R13!,{R0-R1}
	LDR R0,structptr
	LDR R1,[R0,#time_func_entered]
	CMP R1,#0
	BNE abort
	LDR R1,timeptr
	LDR R1,[R1]
	STR R1,[R0,#time_func_entered]
	STR R14,[R0,#func_r14]
	ADR R14,func_exit
abort	LDMIA R13!,{R0-R1}
rep0	MOV R0,R0 ; To be replaced with 1st instr from function
rep1	MOV R0,R0 ; To be replaced with B to 2nd instr from function
func_exit
	STMDB R13!,{R0-R2}
	LDR R0,structptr
	LDR R1,[R0,#time_func_entered]
	LDR R2,timeptr
	LDR R2,[R2]
	SUB R1,R2,R1
	LDR R2,[R0,#time_total]
	ADD R1,R1,R2
	STR R1,[R0,#time_total]
	LDR R2,[R0,#count]
	ADD R2,R2,#1
	STR R2,[R0,#count]
	MOV R1,#0
	STR R1,[R0,#time_func_entered]
	LDR R14,[R0,#func_r14]
	LDMIA R13!,{R0-R2}
	MOV PC,R14
structptr
rep2	MOV R0,R0 ; To be replaced with address of profiling structure
timeptr
rep3	MOV R0,R0 ; To be replaced with time ptr
rep4

jprof2_codeblock
	DCD theblock
jprof2_codeblock_entry
	DCD entryp-theblock
jprof2_codeblock_instr ; Offsets within the blocks, and the block length
	DCD rep0-theblock
jprof2_codeblock_branch
	DCD rep1-theblock
jprof2_codeblock_struct
	DCD rep2-theblock
jprof2_codeblock_timeptr
	DCD rep3-theblock
jprof2_codeblock_length
	DCD rep4-theblock

	END
