File : s-bbcppr-sparc.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . B B . C P U _ P R I M I T I V E S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1999-2002 Universidad Politecnica de Madrid --
10 -- Copyright (C) 2003-2005 The European Space Agency --
11 -- Copyright (C) 2003-2016, AdaCore --
12 -- --
13 -- GNARL is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 3, or (at your option) any later ver- --
16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. --
19 -- --
20 -- --
21 -- --
22 -- --
23 -- --
24 -- You should have received a copy of the GNU General Public License and --
25 -- a copy of the GCC Runtime Library Exception along with this program; --
26 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
27 -- <http://www.gnu.org/licenses/>. --
28 -- --
29 ------------------------------------------------------------------------------
30
31 pragma Restrictions (No_Elaboration_Code);
32
33 with System.Storage_Elements;
34 with System.Multiprocessors;
35 with System.BB.Threads;
36 with System.BB.CPU_Primitives.Multiprocessors;
37 with System.BB.Threads.Queues;
38
39 package body System.BB.CPU_Primitives is
40 use BB.Parameters;
41 use System.BB.Threads;
42 use System.BB.CPU_Primitives.Multiprocessors;
43
44 package SSE renames System.Storage_Elements;
45 use type SSE.Integer_Address;
46 use type SSE.Storage_Offset;
47
48 ----------------
49 -- Local data --
50 ----------------
51
52 SP : constant Context_Id := 6;
53 PC : constant Context_Id := 7;
54 PSR : constant Context_Id := 8;
55 WIM : constant Context_Id := 17;
56 WIN : constant Context_Id := 18;
57 O0 : constant Context_Id := 0;
58 INT : constant Context_Id := 52;
59 -- These are the registers that are initialized: Program Counter, Stack
60 -- Pointer, Window Invalid Mask, and Processor State Register. Moreover,
61 -- the first input argument, the number of register windows to be restored,
62 -- and the interrupt nesting level are also initialized.
63
64 Base_CCR : constant Context_Id := Base_CCR_Context_Index;
65 CCR : constant Context_Id := CCR_Context_Index;
66 pragma Assert (Base_CCR_Context_Index = 53 and then CCR_Context_Index = 54);
67 -- For LEON we allocate two slots for the cache control register at the
68 -- end of the buffer.
69
70 FP : constant SSE.Storage_Offset := 56;
71 -- The frame pointer needs also to be initialized; however, it is not kept
72 -- in the thread descriptor but in the stack, and this value represents the
73 -- offset from the stack pointer (expressed in bytes).
74
75 ----------------------
76 -- Trap definitions --
77 ----------------------
78
79 Instruction_Access_Exception : constant Vector_Id := 16#01#;
80 Illegal_Instruction : constant Vector_Id := 16#02#;
81 Address_Not_Aligned : constant Vector_Id := 16#07#;
82 FP_Exception : constant Vector_Id := 16#08#;
83 Data_Access_Exception : constant Vector_Id := 16#09#;
84 Instruction_Access_Error : constant Vector_Id := 16#21#;
85 Data_Access_Error : constant Vector_Id := 16#29#;
86 Division_By_Zero_Hw : constant Vector_Id := 16#2A#;
87 Data_Store_Error : constant Vector_Id := 16#2B#;
88 Division_By_Zero_Sw : constant Vector_Id := 16#82#;
89
90 type Trap_Entry is
91 record
92 First_Instr : SSE.Integer_Address;
93 Second_Instr : SSE.Integer_Address;
94 Third_Instr : SSE.Integer_Address;
95 Fourth_Instr : SSE.Integer_Address;
96 end record;
97 -- Each entry in the trap table contains the four first instructions that
98 -- will be executed as part of the handler. A trap is a vectored transfer
99 -- of control to the supervisor through a special trap table that contains
100 -- the first four instructions of each trap handler. The base address of
101 -- the table is established by supervisor and the displacement, within the
102 -- table, is determined by the trap type.
103
104 type Trap_Entries_Table is array (Vector_Id) of Trap_Entry;
105 Trap_Table : Trap_Entries_Table;
106 pragma Import (Asm, Trap_Table, "trap_table");
107 -- This is the trap table, that is defined in the crt0 file. This table
108 -- contains the trap entry for all the traps (synchronous and asynchronous)
109 -- defined by the SPARC architecture.
110
111 Common_Handler : Address;
112 pragma Import (Asm, Common_Handler, "common_handler");
113 -- There is a common part that is executed for every trap. This common
114 -- handler executes some prologue, then jumps to the user code, and after
115 -- that executes an epilogue.
116
117 type Vector_Table is array (Vector_Id) of System.Address;
118 User_Vector_Table : Vector_Table;
119 pragma Export (Asm, User_Vector_Table, "user_vector_table");
120 -- In addition to the trap table there is another table that contains the
121 -- addresses for the trap handlers defined by the user. This is used by
122 -- the common wrapper to invoke the correct user-defined handler.
123
124 function Get_CCR return System.Address;
125 pragma Import (Asm, Get_CCR, "get_ccr");
126 pragma Weak_External (Get_CCR);
127 -- Get the value from the hardware Cache Control Register.
128
129 procedure GNAT_Error_Handler (Trap : Vector_Id);
130 -- Trap handler converting synchronous traps to exceptions
131
132 ----------------------------
133 -- Floating point context --
134 ----------------------------
135
136 type Thread_Table is array (System.Multiprocessors.CPU) of Thread_Id;
137 pragma Volatile_Components (Thread_Table);
138 Float_Latest_User_Table : Thread_Table := (others => Null_Thread_Id);
139 pragma Export (Asm, Float_Latest_User_Table, "float_latest_user_table");
140 -- This variable contains the last thread that used the floating point unit
141 -- for each CPU. Hence, it points to the place where the floating point
142 -- state must be stored.
143
144 --------------------
145 -- Context_Switch --
146 --------------------
147
148 procedure Context_Switch is
149 procedure Asm_Context_Switch;
150 pragma Import (Asm, Asm_Context_Switch, "context_switch");
151 begin
152 Asm_Context_Switch;
153 end Context_Switch;
154
155 ------------------------
156 -- Disable_Interrupts --
157 ------------------------
158
159 procedure Disable_Interrupts is
160 procedure Asm_Disable_Interrupts;
161 pragma Import (Asm, Asm_Disable_Interrupts, "disable_interrupts");
162 begin
163 Asm_Disable_Interrupts; -- Replace by inline Asm ???
164 end Disable_Interrupts;
165
166 -----------------------
167 -- Enable_Interrupts --
168 -----------------------
169
170 procedure Enable_Interrupts (Level : Integer) is
171 procedure Asm_Enable_Interrupts (Level : Natural);
172 pragma Import (Asm, Asm_Enable_Interrupts, "enable_interrupts");
173 begin
174 if Level in Interrupt_Priority then
175 Asm_Enable_Interrupts (Level - Interrupt_Priority'First + 1);
176 else
177 Asm_Enable_Interrupts (0);
178 end if;
179 end Enable_Interrupts;
180
181 -----------------
182 -- Get_Context --
183 -----------------
184
185 function Get_Context
186 (Context : Context_Buffer;
187 Index : Context_Id) return Word
188 is
189 begin
190 return Word (Context (Index));
191 end Get_Context;
192
193 ------------------------
194 -- GNAT_Error_Handler --
195 ------------------------
196
197 procedure GNAT_Error_Handler (Trap : Vector_Id) is
198 begin
199 case Trap is
200 when Instruction_Access_Exception =>
201 raise Storage_Error with "instruction access exception";
202 when Illegal_Instruction =>
203 raise Constraint_Error with "illegal instruction";
204 when Address_Not_Aligned =>
205 raise Constraint_Error with "address not aligned";
206 when FP_Exception =>
207 raise Constraint_Error with "floating point exception";
208 when Data_Access_Exception =>
209 raise Constraint_Error with "data access exception";
210 when Instruction_Access_Error =>
211 raise Constraint_Error with "instruction access exception";
212 when Data_Access_Error =>
213 raise Constraint_Error with "data access error";
214 when Division_By_Zero_Hw | Division_By_Zero_Sw =>
215 raise Constraint_Error with "division by zero";
216 when Data_Store_Error =>
217 raise Constraint_Error with "data store error";
218 when others =>
219 raise Program_Error with "unhandled trap";
220 end case;
221 end GNAT_Error_Handler;
222
223 ------------------------
224 -- Initialize_Context --
225 ------------------------
226
227 procedure Initialize_Context
228 (Buffer : not null access Context_Buffer;
229 Program_Counter : System.Address;
230 Argument : System.Address;
231 Stack_Pointer : System.Address)
232 is
233 begin
234 -- The stack must be aligned to 16. 96 bytes are needed for storing
235 -- a whole register window (96 bytes).
236
237 Buffer (SP) :=
238 SSE.To_Address ((SSE.To_Integer (Stack_Pointer) / 16) * 16 - 96);
239
240 -- Initialize PSR with the state expected by the context switch routine.
241 -- Floating point unit is disabled. Traps are enabled, although
242 -- interrupts are disabled (after the context switch only interrupts
243 -- with a lower priority than the task will be masked). The supervisor
244 -- and previous supervisor are set to 1 (the system always operates in
245 -- supervisor mode).
246
247 -- CWP = 0, ET = 1, PS = 1, S = 1, and PIL = 15
248
249 Buffer (PSR) := SSE.To_Address (16#0FE0#);
250
251 -- The WIM is initialized to 2 (corresponding to CWP = 1)
252
253 Buffer (WIM) := SSE.To_Address (2);
254
255 -- The number of windows that must be flushed is initially set to 0
256 -- (only the current window).
257
258 Buffer (WIN) := SSE.To_Address (0);
259
260 -- Initialize PC with the starting address of the task. Substract 8
261 -- to compensate the adjustment made in the context switch routine.
262
263 Buffer (PC) := SSE.To_Address (SSE.To_Integer (Program_Counter) - 8);
264
265 -- The argument to be used by the task wrapper function must be
266 -- passed through the o0 register.
267
268 Buffer (O0) := Argument;
269
270 -- The frame pointer is initialized to be the top of the stack
271
272 declare
273 FP_In_Stack : System.Address;
274 for FP_In_Stack'Address use (Buffer (SP) + FP);
275
276 begin
277 -- Mark the deepest stack frame by setting the frame pointer to zero
278
279 FP_In_Stack := SSE.To_Address (0);
280 end;
281
282 -- The interrupt nesting level is initialized to 0
283
284 Buffer (INT) := SSE.To_Address (0);
285
286 -- For LEON we initialize the cache control register to its value at
287 -- initialization time.
288
289 Buffer (CCR) :=
290 (if Get_CCR'Address = Null_Address then Null_Address else Get_CCR);
291 Buffer (Base_CCR) := Buffer (CCR);
292
293 -- The rest of registers do not need to be initialized
294
295 end Initialize_Context;
296
297 --------------------
298 -- Initialize_CPU --
299 --------------------
300
301 procedure Initialize_CPU is
302 procedure Asm_Initialize_Floating_Point;
303 pragma Import (Asm, Asm_Initialize_Floating_Point,
304 "initialize_floating_point");
305 begin
306 Asm_Initialize_Floating_Point; -- Do in Ada???
307 end Initialize_CPU;
308
309 ----------------------------
310 -- Install_Error_Handlers --
311 ----------------------------
312
313 procedure Install_Error_Handlers is
314 -- Set up trap handler to map synchronous signals to appropriate
315 -- exceptions. Make sure that the handler isn't interrupted by
316 -- another signal that might cause a scheduling event.
317
318 begin
319 -- The division by zero trap may be either a hardware trap (trap type
320 -- 16#2A#) when the integer division istruction is used (on SPARC V8 and
321 -- later) or a software trap (trap type 16#82#) caused by the software
322 -- division implementation in libgcc.
323
324 for J in Vector_Id'Range loop
325 if J in Instruction_Access_Exception
326 | Illegal_Instruction | Address_Not_Aligned | FP_Exception
327 | Data_Access_Exception | Instruction_Access_Error
328 | Data_Access_Error | Division_By_Zero_Hw | Division_By_Zero_Sw
329 | Data_Store_Error
330 then
331 Install_Trap_Handler (GNAT_Error_Handler'Address, J);
332 end if;
333 end loop;
334 end Install_Error_Handlers;
335
336 --------------------------
337 -- Install_Trap_Handler --
338 --------------------------
339
340 procedure Install_Trap_Handler
341 (Service_Routine : Address;
342 Vector : Vector_Id;
343 Synchronous : Boolean := False) is separate;
344
345 -----------------
346 -- Set_Context --
347 -----------------
348
349 procedure Set_Context
350 (Context : in out Context_Buffer;
351 Index : Context_Id;
352 Value : Word)
353 is
354 begin
355 Context (Index) := Address (Value);
356 end Set_Context;
357
358 end System.BB.CPU_Primitives;