1/* Copyright (C) 2000-2021 Free Software Foundation, Inc.
2   This file was pretty much copied from newlib.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 3, or (at your option) any
9later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14General Public License for more details.
15
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23<http://www.gnu.org/licenses/>.  */
24
25#include "crt.h"
26
27#ifdef MMU_SUPPORT
28	/* Section used for exception/timer interrupt stack area */
29	.section .data.vbr.stack,"aw"
30	.align 4
31	.global __ST_VBR
32__ST_VBR:
33	.zero 1024 * 2          /* ; 2k for VBR handlers */
34/* Label at the highest stack address where the stack grows from */
35__timer_stack:
36#endif /* MMU_SUPPORT */
37
38	/* ;----------------------------------------
39	Normal newlib crt1.S */
40
41	! make a place to keep any previous value of the vbr register
42	! this will only have a value if it has been set by redboot (for example)
43	.section .bss
44old_vbr:
45	.long 0
46#ifdef PROFILE
47profiling_enabled:
48	.long 0
49#endif
50
51
52	.section .text
53	.global	start
54	.import ___rtos_profiler_start_timer
55	.weak   ___rtos_profiler_start_timer
56start:
57	mov.l	stack_k,r15
58
59#if defined (__SH3__) || (defined (__SH_FPU_ANY__) && ! defined (__SH2E__) && ! defined (__SH2A__)) || defined (__SH4_NOFPU__)
60#define VBR_SETUP
61	! before zeroing the bss ...
62	! if the vbr is already set to vbr_start then the program has been restarted
63	! (i.e. it is not the first time the program has been run since reset)
64	! reset the vbr to its old value before old_vbr (in bss) is wiped
65	! this ensures that the later code does not create a circular vbr chain
66	stc	vbr, r1
67	mov.l	vbr_start_k, r2
68	cmp/eq	r1, r2
69	bf	0f
70	! reset the old vbr value
71	mov.l	old_vbr_k, r1
72	mov.l	@r1, r2
73	ldc	r2, vbr
740:
75#endif /* VBR_SETUP */
76
77	! zero out bss
78	mov.l	edata_k,r0
79	mov.l	end_k,r1
80	mov	#0,r2
81start_l:
82	mov.l	r2,@r0
83	add	#4,r0
84	cmp/ge	r0,r1
85	bt	start_l
86
87#if defined (__SH_FPU_ANY__)
88	mov.l set_fpscr_k, r1
89	mov #4,r4
90	jsr @r1
91	shll16 r4	! Set DN bit (flush denormal inputs to zero)
92	lds r3,fpscr	! Switch to default precision
93#endif /* defined (__SH_FPU_ANY__) */
94
95#ifdef VBR_SETUP
96	! save the existing contents of the vbr
97	! there will only be a prior value when using something like redboot
98	! otherwise it will be zero
99	stc	vbr, r1
100	mov.l	old_vbr_k, r2
101	mov.l	r1, @r2
102	! setup vbr
103	mov.l	vbr_start_k, r1
104	ldc	r1,vbr
105#endif /* VBR_SETUP */
106
107	! if an rtos is exporting a timer start fn,
108	! then pick up an SR which does not enable ints
109	! (the rtos will take care of this)
110	mov.l rtos_start_fn, r0
111	mov.l sr_initial_bare, r1
112	tst	r0, r0
113	bt	set_sr
114
115	mov.l sr_initial_rtos, r1
116
117set_sr:
118	! Set status register (sr)
119	ldc	r1, sr
120
121	! arrange for exit to call fini
122	mov.l	atexit_k,r0
123	mov.l	fini_k,r4
124	jsr	@r0
125	nop
126
127#ifdef PROFILE
128	! arrange for exit to call _mcleanup (via stop_profiling)
129	mova    stop_profiling,r0
130	mov.l   atexit_k,r1
131	jsr     @r1
132	mov	r0, r4
133
134	! Call profiler startup code
135	mov.l monstartup_k, r0
136	mov.l start_k, r4
137	mov.l etext_k, r5
138	jsr @r0
139	nop
140
141	! enable profiling trap
142	! until now any trap 33s will have been ignored
143	! This means that all library functions called before this point
144	! (directly or indirectly) may have the profiling trap at the start.
145	! Therefore, only mcount itself may not have the extra header.
146	mov.l	profiling_enabled_k2, r0
147	mov	#1, r1
148	mov.l	r1, @r0
149#endif /* PROFILE */
150
151	! call init
152	mov.l	init_k,r0
153	jsr	@r0
154	nop
155
156	! call the mainline
157	mov.l	main_k,r0
158	jsr	@r0
159	nop
160
161	! call exit
162	mov	r0,r4
163	mov.l	exit_k,r0
164	jsr	@r0
165	nop
166
167		.balign 4
168#ifdef PROFILE
169stop_profiling:
170	# stop mcount counting
171	mov.l	profiling_enabled_k2, r0
172	mov	#0, r1
173	mov.l	r1, @r0
174
175	# call mcleanup
176	mov.l	mcleanup_k, r0
177	jmp	@r0
178	nop
179
180		.balign 4
181mcleanup_k:
182	.long __mcleanup
183monstartup_k:
184	.long ___monstartup
185profiling_enabled_k2:
186	.long profiling_enabled
187start_k:
188	.long _start
189etext_k:
190	.long __etext
191#endif /* PROFILE */
192
193	.align 2
194#if defined (__SH_FPU_ANY__)
195set_fpscr_k:
196	.long	___set_fpscr
197#endif /*  defined (__SH_FPU_ANY__) */
198
199stack_k:
200	.long	_stack
201edata_k:
202	.long	_edata
203end_k:
204	.long	_end
205main_k:
206	.long	___setup_argv_and_call_main
207exit_k:
208	.long	_exit
209atexit_k:
210	.long	_atexit
211init_k:
212	.long	GLOBAL(_init)
213fini_k:
214	.long	GLOBAL(_fini)
215#ifdef VBR_SETUP
216old_vbr_k:
217	.long	old_vbr
218vbr_start_k:
219	.long	vbr_start
220#endif /* VBR_SETUP */
221
222sr_initial_rtos:
223	! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work.
224	! Whether profiling or not, keep interrupts masked,
225	! the RTOS will enable these if required.
226	.long 0x600000f1
227
228rtos_start_fn:
229	.long ___rtos_profiler_start_timer
230
231#ifdef PROFILE
232sr_initial_bare:
233	! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work.
234	! For bare machine, we need to enable interrupts to get profiling working
235	.long 0x60000001
236#else
237
238sr_initial_bare:
239	! Privileged mode RB 1 BL 0. Keep BL 0 to allow default trap handlers to work.
240	! Keep interrupts disabled - the application will enable as required.
241	.long 0x600000f1
242#endif
243
244	! supplied for backward compatibility only, in case of linking
245	! code whose main() was compiled with an older version of GCC.
246	.global ___main
247___main:
248	rts
249	nop
250#ifdef VBR_SETUP
251! Exception handlers
252	.section .text.vbr, "ax"
253vbr_start:
254
255	.org 0x100
256vbr_100:
257#ifdef PROFILE
258	! Note on register usage.
259	! we use r0..r3 as scratch in this code. If we are here due to a trapa for profiling
260	! then this is OK as we are just before executing any function code.
261	! The other r4..r7 we save explicityl on the stack
262	! Remaining registers are saved by normal ABI conventions and we assert we do not
263	! use floating point registers.
264	mov.l expevt_k1, r1
265	mov.l @r1, r1
266	mov.l event_mask, r0
267	and r0,r1
268	mov.l trapcode_k, r2
269	cmp/eq r1,r2
270	bt 1f
271	bra handler_100   ! if not a trapa, go to default handler
272	nop
2731:
274	mov.l trapa_k, r0
275	mov.l @r0, r0
276	shlr2 r0      ! trapa code is shifted by 2.
277	cmp/eq #33, r0
278	bt 2f
279	bra handler_100
280	nop
2812:
282
283	! If here then it looks like we have trap #33
284	! Now we need to call mcount with the following convention
285	! Save and restore r4..r7
286	mov.l	r4,@-r15
287	mov.l	r5,@-r15
288	mov.l	r6,@-r15
289	mov.l	r7,@-r15
290	sts.l	pr,@-r15
291
292	! r4 is frompc.
293	! r5 is selfpc
294	! r0 is the branch back address.
295	! The code sequence emitted by gcc for the profiling trap is
296	! .align 2
297	! trapa #33
298	! .align 2
299	! .long lab Where lab is planted by the compiler. This is the address
300	! of a datum that needs to be incremented.
301	sts pr,  r4     ! frompc
302	stc spc, r5	! selfpc
303	mov #2, r2
304	not r2, r2      ! pattern to align to 4
305	and r2, r5      ! r5 now has aligned address
306!	add #4, r5      ! r5 now has address of address
307	mov r5, r2      ! Remember it.
308!	mov.l @r5, r5   ! r5 has value of lable (lab in above example)
309	add #8, r2
310	ldc r2, spc     ! our return address avoiding address word
311
312	! only call mcount if profiling is enabled
313	mov.l profiling_enabled_k, r0
314	mov.l @r0, r0
315	cmp/eq #0, r0
316	bt 3f
317	! call mcount
318	mov.l mcount_k, r2
319	jsr @r2
320	nop
3213:
322	lds.l @r15+,pr
323	mov.l @r15+,r7
324	mov.l @r15+,r6
325	mov.l @r15+,r5
326	mov.l @r15+,r4
327	rte
328	nop
329	.balign 4
330event_mask:
331	.long 0xfff
332trapcode_k:
333	.long 0x160
334expevt_k1:
335	.long 0xff000024 ! Address of expevt
336trapa_k:
337	.long 0xff000020
338mcount_k:
339	.long __call_mcount
340profiling_enabled_k:
341	.long profiling_enabled
342#endif
343	! Non profiling case.
344handler_100:
345	mov.l 2f, r0     ! load the old vbr setting (if any)
346	mov.l @r0, r0
347	cmp/eq #0, r0
348	bf 1f
349	! no previous vbr - jump to own generic handler
350	bra handler
351	nop
3521:	! there was a previous handler - chain them
353	add #0x7f, r0	 ! 0x7f
354	add #0x7f, r0	 ! 0xfe
355	add #0x2, r0     ! add 0x100 without corrupting another register
356	jmp @r0
357	nop
358	.balign 4
3592:
360	.long old_vbr
361
362	.org 0x400
363vbr_400:	! Should be at vbr+0x400
364	mov.l 2f, r0     ! load the old vbr setting (if any)
365	mov.l @r0, r0
366	cmp/eq #0, r0
367	! no previous vbr - jump to own generic handler
368	bt handler
369	! there was a previous handler - chain them
370	rotcr r0
371	rotcr r0
372	add #0x7f, r0	 ! 0x1fc
373	add #0x7f, r0	 ! 0x3f8
374	add #0x02, r0	 ! 0x400
375	rotcl r0
376	rotcl r0	 ! Add 0x400 without corrupting another register
377	jmp @r0
378	nop
379	.balign 4
3802:
381	.long old_vbr
382handler:
383	/* If the trap handler is there call it */
384	mov.l	superh_trap_handler_k, r0
385	cmp/eq	#0, r0       ! True if zero.
386	bf 3f
387	bra   chandler
388	nop
3893:
390	! Here handler available, call it.
391	/* Now call the trap handler with as much of the context unchanged as possible.
392	   Move trapping address into PR to make it look like the trap point */
393	stc spc, r1
394	lds r1, pr
395	mov.l expevt_k, r4
396	mov.l @r4, r4 ! r4 is value of expevt, first parameter.
397	mov r1, r5   ! Remember trapping pc.
398	mov r1, r6   ! Remember trapping pc.
399	mov.l chandler_k, r1
400	mov.l superh_trap_handler_k, r2
401	! jmp to trap handler to avoid disturbing pr.
402	jmp @r2
403	nop
404
405	.org 0x600
406vbr_600:
407#ifdef PROFILE
408	! Should be at vbr+0x600
409	! Now we are in the land of interrupts so need to save more state.
410	! Save register state
411	mov.l interrupt_stack_k, r15 ! r15 has been saved to sgr.
412	mov.l	r0,@-r15
413	mov.l	r1,@-r15
414	mov.l	r2,@-r15
415	mov.l	r3,@-r15
416	mov.l	r4,@-r15
417	mov.l	r5,@-r15
418	mov.l	r6,@-r15
419	mov.l	r7,@-r15
420	sts.l	pr,@-r15
421	sts.l	mach,@-r15
422	sts.l	macl,@-r15
423#if defined(__SH_FPU_ANY__)
424	! Save fpul and fpscr, save fr0-fr7 in 64 bit mode
425	! and set the pervading precision for the timer_handler
426	mov	#0,r0
427	sts.l	fpul,@-r15
428	sts.l	fpscr,@-r15
429	lds	r0,fpscr	! Clear fpscr
430	fmov	fr0,@-r15
431	fmov	fr1,@-r15
432	fmov	fr2,@-r15
433	fmov	fr3,@-r15
434	mov.l	pervading_precision_k,r0
435	fmov	fr4,@-r15
436	fmov	fr5,@-r15
437	mov.l	@r0,r0
438	fmov	fr6,@-r15
439	fmov	fr7,@-r15
440	lds	r0,fpscr
441#endif /* __SH_FPU_ANY__ */
442	! Pass interrupted pc to timer_handler as first parameter (r4).
443	stc    spc, r4
444	mov.l timer_handler_k, r0
445	jsr @r0
446	nop
447#if defined(__SH_FPU_ANY__)
448	mov	#0,r0
449	lds	r0,fpscr	! Clear the fpscr
450	fmov	@r15+,fr7
451	fmov	@r15+,fr6
452	fmov	@r15+,fr5
453	fmov	@r15+,fr4
454	fmov	@r15+,fr3
455	fmov	@r15+,fr2
456	fmov	@r15+,fr1
457	fmov	@r15+,fr0
458	lds.l	@r15+,fpscr
459	lds.l	@r15+,fpul
460#endif /* __SH_FPU_ANY__ */
461	lds.l @r15+,macl
462	lds.l @r15+,mach
463	lds.l @r15+,pr
464	mov.l @r15+,r7
465	mov.l @r15+,r6
466	mov.l @r15+,r5
467	mov.l @r15+,r4
468	mov.l @r15+,r3
469	mov.l @r15+,r2
470	mov.l @r15+,r1
471	mov.l @r15+,r0
472	stc sgr, r15    ! Restore r15, destroyed by this sequence.
473	rte
474	nop
475#if defined(__SH_FPU_ANY__)
476	.balign 4
477pervading_precision_k:
478	.long GLOBAL(__fpscr_values)+4
479#endif
480#else
481	mov.l 2f, r0     ! Load the old vbr setting (if any).
482	mov.l @r0, r0
483	cmp/eq #0, r0
484	! no previous vbr - jump to own handler
485	bt chandler
486	! there was a previous handler - chain them
487	rotcr r0
488	rotcr r0
489	add #0x7f, r0	 ! 0x1fc
490	add #0x7f, r0	 ! 0x3f8
491	add #0x7f, r0	 ! 0x5f4
492	add #0x03, r0	 ! 0x600
493	rotcl r0
494	rotcl r0	 ! Add 0x600 without corrupting another register
495	jmp @r0
496	nop
497	.balign 4
4982:
499	.long old_vbr
500#endif	 /* PROFILE code */
501chandler:
502	mov.l expevt_k, r4
503	mov.l @r4, r4 ! r4 is value of expevt hence making this the return code
504	mov.l handler_exit_k,r0
505	jsr   @r0
506	nop
507	! We should never return from _exit but in case we do we would enter the
508	! the following tight loop
509limbo:
510	bra limbo
511	nop
512	.balign 4
513#ifdef PROFILE
514interrupt_stack_k:
515	.long __timer_stack	! The high end of the stack
516timer_handler_k:
517	.long __profil_counter
518#endif
519expevt_k:
520	.long 0xff000024 ! Address of expevt
521chandler_k:
522	.long chandler
523superh_trap_handler_k:
524	.long	__superh_trap_handler
525handler_exit_k:
526	.long _exit
527	.align 2
528! Simulated compile of trap handler.
529	.section	.debug_abbrev,"",@progbits
530.Ldebug_abbrev0:
531	.section	.debug_info,"",@progbits
532.Ldebug_info0:
533	.section	.debug_line,"",@progbits
534.Ldebug_line0:
535	.text
536.Ltext0:
537	.align 5
538	.type	__superh_trap_handler,@function
539__superh_trap_handler:
540.LFB1:
541	mov.l	r14,@-r15
542.LCFI0:
543	add	#-4,r15
544.LCFI1:
545	mov	r15,r14
546.LCFI2:
547	mov.l	r4,@r14
548	lds	r1, pr
549	add	#4,r14
550	mov	r14,r15
551	mov.l	@r15+,r14
552	rts
553	nop
554.LFE1:
555.Lfe1:
556	.size	__superh_trap_handler,.Lfe1-__superh_trap_handler
557	.section	.debug_frame,"",@progbits
558.Lframe0:
559	.ualong	.LECIE0-.LSCIE0
560.LSCIE0:
561	.ualong	0xffffffff
562	.byte	0x1
563	.string	""
564	.uleb128 0x1
565	.sleb128 -4
566	.byte	0x11
567	.byte	0xc
568	.uleb128 0xf
569	.uleb128 0x0
570	.align 2
571.LECIE0:
572.LSFDE0:
573	.ualong	.LEFDE0-.LASFDE0
574.LASFDE0:
575	.ualong	.Lframe0
576	.ualong	.LFB1
577	.ualong	.LFE1-.LFB1
578	.byte	0x4
579	.ualong	.LCFI0-.LFB1
580	.byte	0xe
581	.uleb128 0x4
582	.byte	0x4
583	.ualong	.LCFI1-.LCFI0
584	.byte	0xe
585	.uleb128 0x8
586	.byte	0x8e
587	.uleb128 0x1
588	.byte	0x4
589	.ualong	.LCFI2-.LCFI1
590	.byte	0xd
591	.uleb128 0xe
592	.align 2
593.LEFDE0:
594	.text
595.Letext0:
596	.section	.debug_info
597	.ualong	0xb3
598	.uaword	0x2
599	.ualong	.Ldebug_abbrev0
600	.byte	0x4
601	.uleb128 0x1
602	.ualong	.Ldebug_line0
603	.ualong	.Letext0
604	.ualong	.Ltext0
605	.string	"trap_handler.c"
606	.string	"xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
607	.string	"GNU C 3.2 20020529 (experimental)"
608	.byte	0x1
609	.uleb128 0x2
610	.ualong	0xa6
611	.byte	0x1
612	.string	"_superh_trap_handler"
613	.byte	0x1
614	.byte	0x2
615	.byte	0x1
616	.ualong	.LFB1
617	.ualong	.LFE1
618	.byte	0x1
619	.byte	0x5e
620	.uleb128 0x3
621	.string	"trap_reason"
622	.byte	0x1
623	.byte	0x1
624	.ualong	0xa6
625	.byte	0x2
626	.byte	0x91
627	.sleb128 0
628	.byte	0x0
629	.uleb128 0x4
630	.string	"unsigned int"
631	.byte	0x4
632	.byte	0x7
633	.byte	0x0
634	.section	.debug_abbrev
635	.uleb128 0x1
636	.uleb128 0x11
637	.byte	0x1
638	.uleb128 0x10
639	.uleb128 0x6
640	.uleb128 0x12
641	.uleb128 0x1
642	.uleb128 0x11
643	.uleb128 0x1
644	.uleb128 0x3
645	.uleb128 0x8
646	.uleb128 0x1b
647	.uleb128 0x8
648	.uleb128 0x25
649	.uleb128 0x8
650	.uleb128 0x13
651	.uleb128 0xb
652	.byte	0x0
653	.byte	0x0
654	.uleb128 0x2
655	.uleb128 0x2e
656	.byte	0x1
657	.uleb128 0x1
658	.uleb128 0x13
659	.uleb128 0x3f
660	.uleb128 0xc
661	.uleb128 0x3
662	.uleb128 0x8
663	.uleb128 0x3a
664	.uleb128 0xb
665	.uleb128 0x3b
666	.uleb128 0xb
667	.uleb128 0x27
668	.uleb128 0xc
669	.uleb128 0x11
670	.uleb128 0x1
671	.uleb128 0x12
672	.uleb128 0x1
673	.uleb128 0x40
674	.uleb128 0xa
675	.byte	0x0
676	.byte	0x0
677	.uleb128 0x3
678	.uleb128 0x5
679	.byte	0x0
680	.uleb128 0x3
681	.uleb128 0x8
682	.uleb128 0x3a
683	.uleb128 0xb
684	.uleb128 0x3b
685	.uleb128 0xb
686	.uleb128 0x49
687	.uleb128 0x13
688	.uleb128 0x2
689	.uleb128 0xa
690	.byte	0x0
691	.byte	0x0
692	.uleb128 0x4
693	.uleb128 0x24
694	.byte	0x0
695	.uleb128 0x3
696	.uleb128 0x8
697	.uleb128 0xb
698	.uleb128 0xb
699	.uleb128 0x3e
700	.uleb128 0xb
701	.byte	0x0
702	.byte	0x0
703	.byte	0x0
704	.section	.debug_pubnames,"",@progbits
705	.ualong	0x27
706	.uaword	0x2
707	.ualong	.Ldebug_info0
708	.ualong	0xb7
709	.ualong	0x67
710	.string	"_superh_trap_handler"
711	.ualong	0x0
712	.section	.debug_aranges,"",@progbits
713	.ualong	0x1c
714	.uaword	0x2
715	.ualong	.Ldebug_info0
716	.byte	0x4
717	.byte	0x0
718	.uaword	0x0
719	.uaword	0x0
720	.ualong	.Ltext0
721	.ualong	.Letext0-.Ltext0
722	.ualong	0x0
723	.ualong	0x0
724#endif /* VBR_SETUP */
725