1// picoChip ASM file
2//
3//   Support for 16-bit signed division/modulus.
4//
5//   Copyright (C) 2003, 2004, 2005, 2008, 2009  Free Software Foundation, Inc.
6//   Contributed by picoChip Designs Ltd.
7//   Maintained by Daniel Towner (daniel.towner@picochip.com)
8//
9//   This file is free software; you can redistribute it and/or modify it
10//   under the terms of the GNU General Public License as published by the
11//   Free Software Foundation; either version 3, or (at your option) any
12//   later version.
13//
14//   This file is distributed in the hope that it will be useful, but
15//   WITHOUT ANY WARRANTY; without even the implied warranty of
16//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17//   General Public License for more details.
18//
19//   Under Section 7 of GPL version 3, you are granted additional
20//   permissions described in the GCC Runtime Library Exception, version
21//   3.1, as published by the Free Software Foundation.
22//
23//   You should have received a copy of the GNU General Public License and
24//   a copy of the GCC Runtime Library Exception along with this program;
25//   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
26//   <http://www.gnu.org/licenses/>.
27
28.section .text
29
30.align 8		
31.global __divmodhi4
32__divmodhi4:
33_picoMark_FUNCTION_BEGIN=
34
35// picoChip Function Prologue : &__divmodhi4 = 4 bytes
36
37	// 16-bit signed division. Most of the special cases are dealt
38	// with by the 15-bit signed division library (e.g., division by
39	// zero, division by 1, and so on). This wrapper simply inverts	
40	// any negative inputs, calls the 15-bit library, and flips any
41	// results as necessary.  The
42	// only special cases to be handled here are where either the 
43	// divisor or the dividend are the maximum negative values.
44
45	// Encode r5 with a bit pattern which indicates whether the
46	// outputs of the division must be negated. The MSB will be set
47	// to the sign of the dividend (which controls the remainder's
48	// sign), while the LSB will store the XOR of the two signs,
49	// which indicates the quotient's sign. R5 is not modified by the
50	// 15-bit divmod routine.
51	sub.0 r1,16#8000#,r15 \ asr.1 r0,15,r4
52	beq divisorIsLargestNegative \ lsr.0 r1,15,r3
53=->	sub.0 r0,16#8000#,r15 \ xor.1 r3,r4,r5
54
55	// Handle least negative dividend with a special case. Note that the
56	// absolute value of the divisor is also computed here.
57	add.0 [asr r1,15],r1,r3	\ beq dividendIsLargestNegative
58=->	xor.0 [asr r1,15],r3,r1 \ stw lr,(fp)-1	
59	
60	// Compute the absolute value of the dividend, and call the main
61	// divide routine.
62	add.0 r4,r0,r2 \ jl (&__divmod15)  // fn_call &__divmod15
63=->	xor.0 r4,r2,r0
64
65handleNegatedResults:	
66	// Speculatively store the negation of the results.
67	sub.0 0,r0,r2 \ sub.1 0,r1,r3
68
69	// Does the quotient need negating? The LSB indicates this.
70	and.0 r5,1,r15 \ ldw (fp)-1,lr
71	copyne r2,r0
72		
73	asr.0 r5,15,r15 \ jr (lr)
74=->	copyne r3,r1
75	
76dividendIsLargestNegative:
77
78	// Divide the constant -32768. Use the Hacker's Delight
79	// algorithm (i.e., ((dividend / 2) / divisor) * 2) gives
80	// approximate answer). This code is a special case, so no
81	// great effort is made to make it fast, only to make it
82	// small.
83
84	lsr.0 r0,1,r0 \ jl (&__divmod15)  // fn_call &__divmod15
85=->	stw r1,(fp)-2
86
87	// Load the original divisor, and compute the new quotient and
88	// remainder.	
89	lsl.0 r0,1,r0 \ ldw (fp)-2,r3
90	lsl.0 r1,1,r1 // Fill stall slot
91
92	// The error in the quotient is 0 or 1. The error can be determined
93	// by comparing the remainder to the original divisor. If the
94	// remainder is bigger, then an error of 1 has been introduced,
95	// which must be fixed.
96	sub.0 r1,r3,r15
97	blo noCompensationForError
98=->	nop	
99	add.0 r0,1,r0 \ sub.1 r1,r3,r1
100noCompensationForError:
101	bra handleNegatedResults
102=->	nop
103
104divisorIsLargestNegative:	
105	// The flags indicate whether the dividend is also the maximum negative
106	copy.0 r0,r1 \ copy.1 0,r0
107	copyeq r0,r1 \ jr (lr)
108=->	copyeq 1,r0
109
110_picoMark_FUNCTION_END=
111// picoChip Function Epilogue : __divmodhi4
112	
113
114//============================================================================
115// All DWARF information between this marker, and the END OF DWARF
116// marker should be included in the source file. Search for
117// FUNCTION_STACK_SIZE_GOES_HERE and FUNCTION NAME GOES HERE, and
118// provide the relevent information. Add markers called
119// _picoMark_FUNCTION_BEGIN and _picoMark_FUNCTION_END around the
120// function in question.
121//============================================================================
122
123//============================================================================
124// Frame information. 
125//============================================================================
126
127.section .debug_frame
128_picoMark_DebugFrame=
129
130// Common CIE header.
131.unalignedInitLong _picoMark_CieEnd-_picoMark_CieBegin
132_picoMark_CieBegin=
133.unalignedInitLong 0xffffffff
134.initByte 0x1	// CIE Version
135.ascii 16#0#	// CIE Augmentation
136.uleb128 0x1	// CIE Code Alignment Factor
137.sleb128 2	// CIE Data Alignment Factor
138.initByte 0xc	// CIE RA Column
139.initByte 0xc	// DW_CFA_def_cfa
140.uleb128 0xd
141.uleb128 0x0
142.align 2
143_picoMark_CieEnd=
144
145// FDE 
146_picoMark_LSFDE0I900821033007563=
147.unalignedInitLong _picoMark_FdeEnd-_picoMark_FdeBegin
148_picoMark_FdeBegin=
149.unalignedInitLong _picoMark_DebugFrame	// FDE CIE offset
150.unalignedInitWord _picoMark_FUNCTION_BEGIN	// FDE initial location
151.unalignedInitWord _picoMark_FUNCTION_END-_picoMark_FUNCTION_BEGIN
152.initByte 0xe	// DW_CFA_def_cfa_offset
153.uleb128 0x4	// <-- FUNCTION_STACK_SIZE_GOES_HERE
154.initByte 0x4	// DW_CFA_advance_loc4
155.unalignedInitLong _picoMark_FUNCTION_END-_picoMark_FUNCTION_BEGIN
156.initByte 0xe	// DW_CFA_def_cfa_offset
157.uleb128 0x0
158.align 2
159_picoMark_FdeEnd=
160
161//============================================================================
162// Abbrevation information.
163//============================================================================
164
165.section .debug_abbrev
166_picoMark_ABBREVIATIONS=
167
168.section .debug_abbrev
169	.uleb128 0x1	// (abbrev code)
170	.uleb128 0x11	// (TAG: DW_TAG_compile_unit)
171	.initByte 0x1	// DW_children_yes
172	.uleb128 0x10	// (DW_AT_stmt_list)
173	.uleb128 0x6	// (DW_FORM_data4)
174	.uleb128 0x12	// (DW_AT_high_pc)
175	.uleb128 0x1	// (DW_FORM_addr)
176	.uleb128 0x11	// (DW_AT_low_pc)
177	.uleb128 0x1	// (DW_FORM_addr)
178	.uleb128 0x25	// (DW_AT_producer)
179	.uleb128 0x8	// (DW_FORM_string)
180	.uleb128 0x13	// (DW_AT_language)
181	.uleb128 0x5	// (DW_FORM_data2)
182	.uleb128 0x3	// (DW_AT_name)
183	.uleb128 0x8	// (DW_FORM_string)
184.initByte 0x0
185.initByte 0x0
186
187	.uleb128 0x2	;# (abbrev code)
188	.uleb128 0x2e	;# (TAG: DW_TAG_subprogram)
189.initByte 0x0	;# DW_children_no
190	.uleb128 0x3	;# (DW_AT_name)
191	.uleb128 0x8	;# (DW_FORM_string)
192	.uleb128 0x11	;# (DW_AT_low_pc)
193	.uleb128 0x1	;# (DW_FORM_addr)
194	.uleb128 0x12	;# (DW_AT_high_pc)
195	.uleb128 0x1	;# (DW_FORM_addr)
196.initByte 0x0
197.initByte 0x0
198
199.initByte 0x0
200
201//============================================================================
202// Line information. DwarfLib requires this to be present, but it can
203// be empty.
204//============================================================================
205
206.section .debug_line
207_picoMark_LINES=
208
209//============================================================================
210// Debug Information
211//============================================================================
212.section .debug_info
213
214//Fixed header.
215.unalignedInitLong _picoMark_DEBUG_INFO_END-_picoMark_DEBUG_INFO_BEGIN
216_picoMark_DEBUG_INFO_BEGIN=
217.unalignedInitWord 0x2
218.unalignedInitLong _picoMark_ABBREVIATIONS
219.initByte 0x2
220
221// Compile unit information.
222.uleb128 0x1	// (DIE 0xb) DW_TAG_compile_unit)
223.unalignedInitLong _picoMark_LINES
224.unalignedInitWord _picoMark_FUNCTION_END
225.unalignedInitWord _picoMark_FUNCTION_BEGIN
226// Producer is `picoChip'
227.ascii 16#70# 16#69# 16#63# 16#6f# 16#43# 16#68# 16#69# 16#70# 16#00#
228.unalignedInitWord 0xcafe // ASM language
229.ascii 16#0# // Name. DwarfLib expects this to be present.
230
231.uleb128 0x2	;# (DIE DW_TAG_subprogram)
232
233// FUNCTION NAME GOES HERE. Use `echo name | od -t x1' to get the hex. Each hex
234// digit is specified using the format 16#XX#
235.ascii 16#5f# 16#64# 16#69# 16#76# 16#6d# 16#6f# 16#64# 16#68# 16#69# 16#34# 16#0# // Function name `_divmodhi4'
236.unalignedInitWord _picoMark_FUNCTION_BEGIN	// DW_AT_low_pc
237.unalignedInitWord _picoMark_FUNCTION_END	// DW_AT_high_pc
238
239.initByte 0x0	// end of compile unit children.
240
241_picoMark_DEBUG_INFO_END=
242
243//============================================================================
244// END OF DWARF
245//============================================================================
246.section .endFile
247