File : s-bbbosu-erc32.adb
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . B B . B O A R D _ S U P P O R T --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1999-2002 Universidad Politecnica de Madrid --
10 -- Copyright (C) 2003-2006 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 -- GNARL was developed by the GNARL team at Florida State University. --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
31 -- --
32 -- The port of GNARL to bare board targets was initially developed by the --
33 -- Real-Time Systems Group at the Technical University of Madrid. --
34 -- --
35 ------------------------------------------------------------------------------
36
37 -- There are page numbers in the comments below, please provide the reference
38 -- to the document (here in this header) to which these references apply ???
39
40 pragma Restrictions (No_Elaboration_Code);
41
42 with System.BB.Board_Support.ERC32;
43 with System.BB.Parameters;
44
45 package body System.BB.Board_Support is
46 use type ERC32.Scaler_8;
47 use type ERC32.Timers_Counter;
48 use CPU_Primitives;
49
50 package Registers renames ERC32;
51
52 -----------------------
53 -- Local Definitions --
54 -----------------------
55
56 Periodic_Scaler : constant := 0;
57 -- In order to obtain the highest granularity of the clock we set the
58 -- scaler to 0.
59
60 Alarm_Scaler : constant := 0;
61 -- In order to obtain the highest resolution of the alarm timer we set
62 -- the scaler to 0.
63
64 Periodic_Count : constant := Registers.Timers_Counter'Last - 1;
65 -- Value to be loaded in the clock counter to accomplish the
66 -- Clock_Interrupt_Period.
67 --
68 -- One is subtracted from Timers_Counter'Last because when the Scaler is
69 -- set to 0, the timeout period will be the counter reload value plus 1.
70
71 -- Constants defining the external interrupts
72
73 General_Purpose_Timer : constant System.BB.Interrupts.Interrupt_ID := 12;
74
75 Timer_Control_Mirror : Registers.Timer_Control_Register;
76 pragma Volatile (Timer_Control_Mirror);
77 -- Timer_Control register cannot be read. So the following object holds a
78 -- copy of the Timer_Control register value.
79
80 ----------------------
81 -- Local Procedures --
82 ----------------------
83
84 procedure Stop_Watch_Dog;
85 pragma Inline (Stop_Watch_Dog);
86 -- Stop the watch dog timer
87
88 procedure Initialize_Memory;
89 pragma Inline (Initialize_Memory);
90 -- Initialize the memory on the board
91
92 procedure Initialize_Clock;
93 -- Perform all the initialization related to the clock
94
95 ------------------------
96 -- Alarm_Interrupt_ID --
97 ------------------------
98
99 function Alarm_Interrupt_ID return Interrupts.Interrupt_ID is
100 begin
101 return General_Purpose_Timer;
102 end Alarm_Interrupt_ID;
103
104 ---------------------------
105 -- Clear_Alarm_Interrupt --
106 ---------------------------
107
108 procedure Clear_Alarm_Interrupt is
109 begin
110 -- From MEC Specification Document (MCD/SPC/0009/SE) page 35
111
112 -- The MEC includes a specific register called Interrupt Pending
113 -- Register, which reflects the pending interrupts.
114
115 -- The interrupts in the IPR are cleared automatically when the
116 -- interrupt is acknowledged. The MEC will sample the trap address in
117 -- order to know which bit to clear. Therefore, this procedure has a
118 -- null body for this target.
119
120 null;
121 end Clear_Alarm_Interrupt;
122
123 -----------------------------
124 -- Clear_Interrupt_Request --
125 -----------------------------
126
127 procedure Clear_Interrupt_Request
128 (Interrupt : System.BB.Interrupts.Interrupt_ID)
129 is
130 begin
131 -- Nothing to do for the IPIC
132
133 null;
134 end Clear_Interrupt_Request;
135
136 --------------------------
137 -- Clear_Poke_Interrupt --
138 --------------------------
139
140 procedure Clear_Poke_Interrupt is
141 begin
142 -- No Poke interrupt available for ERC32
143
144 raise Program_Error;
145 end Clear_Poke_Interrupt;
146
147 ---------------------------
148 -- Priority_Of_Interrupt --
149 ---------------------------
150
151 function Priority_Of_Interrupt
152 (Interrupt : System.BB.Interrupts.Interrupt_ID) return System.Any_Priority
153 is
154 begin
155 -- Assert that it is a real interrupt
156
157 pragma Assert (Interrupt /= System.BB.Interrupts.No_Interrupt);
158
159 return (Any_Priority (Interrupt) + Interrupt_Priority'First - 1);
160 end Priority_Of_Interrupt;
161
162 ----------------------
163 -- Initialize_Board --
164 ----------------------
165
166 procedure Initialize_Board is
167 begin
168 -- The initialization of the ERC32 board consists on stopping the watch
169 -- dog timer, initializing the memory, and initializing the clock in
170 -- order to have the desired granularity and range.
171
172 Stop_Watch_Dog;
173 Initialize_Memory;
174 Initialize_Clock;
175 end Initialize_Board;
176
177 ----------------------
178 -- Initialize_Clock --
179 ----------------------
180
181 procedure Initialize_Clock is
182 Real_Time_Clock_Scaler_Aux : Registers.Real_Time_Clock_Scaler_Register;
183
184 begin
185 -- Set the scaler for the clock
186
187 Real_Time_Clock_Scaler_Aux := Registers.Real_Time_Clock_Scaler;
188 Real_Time_Clock_Scaler_Aux.RTCS := Periodic_Scaler;
189 Registers.Real_Time_Clock_Scaler := Real_Time_Clock_Scaler_Aux;
190
191 -- Load the counter for the clock
192
193 Registers.Real_Time_Clock_Counter := Periodic_Count;
194
195 -- Set the proper bits in mirrored Timer Control Register. The timer
196 -- used for the clock is programmed in periodic mode.
197
198 -- From MEC Specification Document (MCD/SPC/0009/SE) page 50
199
200 -- NOTE: All reserved bits have to be written with zeros in order to
201 -- avoid parity error resulting in a MEC internal error.
202
203 Timer_Control_Mirror.Reserved4 := (others => False);
204 Timer_Control_Mirror.Reserved20 := (others => False);
205
206 Timer_Control_Mirror.RTCCR := True;
207 Timer_Control_Mirror.RTCCL := True;
208 Timer_Control_Mirror.RTCSL := True;
209 Timer_Control_Mirror.RTCSE := True;
210
211 -- Do not modify General Purpose Timer downcounter
212
213 Timer_Control_Mirror.GCL := False;
214 Timer_Control_Mirror.GSL := False;
215
216 -- Write MEC Timer Control Register
217
218 Registers.Timer_Control := Timer_Control_Mirror;
219 end Initialize_Clock;
220
221 -----------------------
222 -- Initialize_Memory --
223 -----------------------
224
225 procedure Initialize_Memory is
226 begin
227 -- Nothing to be done for the ERC32
228
229 null;
230 end Initialize_Memory;
231
232 ------------------------
233 -- Max_Timer_Interval --
234 ------------------------
235
236 function Max_Timer_Interval return Timer_Interval is
237 begin
238 return Timer_Interval'Last;
239 end Max_Timer_Interval;
240
241 -----------------------
242 -- Poke_Interrupt_ID --
243 -----------------------
244
245 function Poke_Interrupt_ID return Interrupts.Interrupt_ID is
246 begin
247 -- No Poke interrupt available for ERC32
248
249 raise Program_Error;
250
251 -- Unreachable code
252
253 return Interrupts.Interrupt_ID'First;
254 end Poke_Interrupt_ID;
255
256 ---------------------------
257 -- Get_Interrupt_Request --
258 ---------------------------
259
260 function Get_Interrupt_Request
261 (Vector : CPU_Primitives.Vector_Id)
262 return System.BB.Interrupts.Interrupt_ID
263 is
264 begin
265 -- The range corresponding to asynchronous traps is in 16#11# .. 16#1F#
266
267 pragma Assert (Vector in 16#11# .. 16#1F#);
268
269 return System.BB.Interrupts.Interrupt_ID (Vector - 16#10#);
270 end Get_Interrupt_Request;
271
272 -------------------------------
273 -- Install_Interrupt_Handler --
274 -------------------------------
275
276 procedure Install_Interrupt_Handler
277 (Handler : Address;
278 Interrupt : Interrupts.Interrupt_ID;
279 Prio : Interrupt_Priority)
280 is
281 pragma Unreferenced (Prio);
282 begin
283 CPU_Primitives.Install_Trap_Handler
284 (Handler, CPU_Primitives.Vector_Id (Interrupt + 16#10#));
285 end Install_Interrupt_Handler;
286
287 ----------------
288 -- Read_Clock --
289 ----------------
290
291 function Read_Clock return Timer_Interval is
292 begin
293 return
294 Timer_Interval (Periodic_Count - Registers.Real_Time_Clock_Counter);
295 end Read_Clock;
296
297 ---------------
298 -- Set_Alarm --
299 ---------------
300
301 procedure Set_Alarm (Ticks : Timer_Interval) is
302 General_Purpose_Timer_Scaler_Aux :
303 Registers.General_Purpose_Timer_Scaler_Register;
304
305 Interrupt_Mask_Aux : Registers.Interrupt_Mask_Register;
306
307 begin
308 -- Alarm Clock downcount will reach 0 in Ticks. The granularity of
309 -- time intervals is equal to Clock Period.
310
311 -- Set the scaler
312
313 General_Purpose_Timer_Scaler_Aux :=
314 Registers.General_Purpose_Timer_Scaler;
315 General_Purpose_Timer_Scaler_Aux.GPTS := Alarm_Scaler;
316 Registers.General_Purpose_Timer_Scaler :=
317 General_Purpose_Timer_Scaler_Aux;
318
319 -- Load the counter
320
321 Registers.General_Purpose_Timer_Counter :=
322 Registers.Timers_Counter (Ticks);
323
324 -- Set the proper bits in mirrored Timer Control Register.
325 -- General Purpose Timer is used in one-shot mode.
326
327 Timer_Control_Mirror.GCR := False;
328
329 Timer_Control_Mirror.GCL := True;
330 Timer_Control_Mirror.GSE := True;
331 Timer_Control_Mirror.GSL := True;
332
333 -- Do not modify Timer downcount
334
335 Timer_Control_Mirror.RTCCL := False;
336 Timer_Control_Mirror.RTCSL := False;
337
338 -- From MEC Specification Document (MCD/SPC/0009/SE) page 50
339
340 -- NOTE: All reserved bits have to be written with zeros in order to
341 -- avoid parity error resulting in a MEC internal error.
342
343 Timer_Control_Mirror.Reserved4 := (others => False);
344 Timer_Control_Mirror.Reserved20 := (others => False);
345
346 -- Write MEC Timer Control Register
347
348 Registers.Timer_Control := Timer_Control_Mirror;
349
350 -- Enable GPT Interrupts
351
352 Interrupt_Mask_Aux := Registers.Interrupt_Mask;
353 Interrupt_Mask_Aux.General_Purpose_Timer := False;
354 Registers.Interrupt_Mask := Interrupt_Mask_Aux;
355 end Set_Alarm;
356
357 --------------------------
358 -- Set_Current_Priority --
359 --------------------------
360
361 procedure Set_Current_Priority (Priority : Integer) is
362 begin
363 null; -- No board-specific actions necessary
364 end Set_Current_Priority;
365
366 --------------------
367 -- Stop_Watch_Dog --
368 --------------------
369
370 procedure Stop_Watch_Dog is
371 begin
372 -- From MEC Specification Document (MCD/SPC/0009/SE) page 39
373
374 -- After system reset or processor reset, the watch dog timer is enabled
375 -- and starts running. By writing to the Trap Door Set after system
376 -- reset, the timer can be disabled.
377
378 Registers.Watchdog_Trap_Door_Set := 0;
379 end Stop_Watch_Dog;
380
381 ----------------------
382 -- Ticks_Per_Second --
383 ----------------------
384
385 function Ticks_Per_Second return Natural is
386 begin
387 -- The prescaler is clocked by the system clock. When it underflows, it
388 -- is reloaded from the prescaler reload register and a timer tick is
389 -- generated. The effective division rate is therefore equal to the
390 -- prescaler reload register value plus 1.
391
392 return Parameters.Clock_Frequency / (Periodic_Scaler + 1);
393 end Ticks_Per_Second;
394
395 end System.BB.Board_Support;