source: soft/giet_vm/giet_drivers/tim_driver.c @ 386

Last change on this file since 386 was 333, checked in by alain, 11 years ago

Cosmetic

File size: 9.1 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////////
2// File     : timer_driver.c
3// Date     : 23/05/2013
4// Author   : alain greiner
5// Copyright (c) UPMC-LIP6
6//////////////////////////////////////////////////////////////////////////////////////
7// The timer_driver.c and timer_driver.h files are part ot the GIET-VM nano-kernel.
8// This driver supports the SoCLib vci_multi_timer component.
9//
10// It can exist several multi_timers in the architecture (at most one per cluster),
11// and each one can contain several timers (called channels).
12//
13// There is two types of timers:
14// - "system" timers : one per processor, used for context switch.
15//   local_id in [0, NB_PROCS_MAX-1],
16// - "user" timers : requested by the task in the mapping_info data structure.
17//   For each user timer, the timer_id is stored in the context of the task.
18// The global index is cluster_xy * (NB_PROCS_MAX + NB_TIM_CHANNELS) + local_id
19//
20// The NB_PROCS_MAX and NB_TIM_CHANNELS values must be defined in hard_config.h file.
21//
22// The virtual base address of the segment associated to a channel is:
23//     SEG_TIM_BASE + cluster_xy * PERI_CLUSTER_INCREMENT + TIMER_SPAN * timer_id
24//
25// The SEG_TIM_BASE and PERI_CLUSTER_INCREMENT must be defined in hard_config.h.
26/////////////////////////////////////////////////////////////////////////////////////
27
28#include <giet_config.h>
29#include <tim_driver.h>
30#include <xcu_driver.h>
31#include <tty_driver.h>
32#include <utils.h>
33
34#if !defined(SEG_TIM_BASE)
35# error: You must define SEG_TIM_BASE in the hard_config.h file
36#endif
37
38#if !defined(PERI_CLUSTER_INCREMENT)
39# error: You must define PERI_CLUSTER_INCREMENT in the hard_config.h file
40#endif
41
42#if !defined(X_SIZE)
43# error: You must define X_SIZE in the hard_config.h file
44#endif
45
46#if !defined(Y_SIZE)
47# error: You must define X_SIZE in the hard_config.h file
48#endif
49
50#if !defined(X_WIDTH)
51# error: You must define X_WIDTH in the hard_config.h file
52#endif
53
54#if !defined(Y_WIDTH)
55# error: You must define X_WIDTH in the hard_config.h file
56#endif
57
58#if !defined(NB_PROCS_MAX)
59# error: You must define NB_PROCS_MAX in the hard_config.h file
60#endif
61
62#if !defined(NB_TIM_CHANNELS)
63#define NB_TIM_CHANNELS 0
64#endif
65
66#if ( (NB_TIM_CHANNELS + NB_PROC_MAX) > 32 )
67# error: NB_TIM_CHANNELS + NB_PROCS_MAX cannot be larger than 32
68#endif
69
70///////////////////  Timer global variables ////////////////////////////////////////
71
72#define in_unckdata __attribute__((section (".unckdata")))
73
74#if (NB_TIM_CHANNELS > 0)
75in_unckdata volatile unsigned char _user_timer_event[(1<<X_WIDTH)*(1<<Y_WIDTH)*NB_TIM_CHANNELS] 
76                        = { [0 ... (((1<<X_WIDTH)*(1<<Y_WIDTH)*NB_TIM_CHANNELS) - 1)] = 0 };
77#endif
78
79////////////////////////////////////////////////////////////////////////////////////
80// This function activates a timer in the vci_timer component
81// by writing in the proper register the period value.
82// It can be used by both the kernel to initialise a "system" timer,
83// or by a task (through a system call) to configure an "user" timer.
84///////////////////////////////////////////////////////////////////////////////////
85void _timer_start( unsigned int cluster_xy, 
86                   unsigned int local_id, 
87                   unsigned int period) 
88{
89#if NB_TIM_CHANNELS
90
91    // parameters checking
92    unsigned int x = cluster_xy >> Y_WIDTH;
93    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
94    if ( (x >= X_SIZE) || (y >= Y_SIZE) || (local_id >= NB_TIM_CHANNELS) )
95    {
96        _printf("[GIET ERROR] in _timer_start()\n");
97        _exit();
98    }
99
100    unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE +
101                                  (cluster_xy * PERI_CLUSTER_INCREMENT) );
102
103    timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period;
104    timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0x3;
105
106#else
107    _printf("[GIET ERROR] _timer_start() should not be called when NB_TIM_CHANNELS is 0\n");
108    _exit();
109#endif
110}
111
112//////////////////////////////////////////////////////////////////////////////
113// This function desactivates a timer in the vci_timer component
114// by writing in the proper register.
115// Returns 0 if success, > 0 if error.
116//////////////////////////////////////////////////////////////////////////////
117void _timer_stop( unsigned int cluster_xy, 
118                  unsigned int local_id) 
119{
120#if NB_TIM_CHANNELS
121
122    // parameters checking
123    unsigned int x = cluster_xy >> Y_WIDTH;
124    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
125    if ( (x >= X_SIZE) || (y >= Y_SIZE) || (local_id >= NB_TIM_CHANNELS) )
126    {
127        _printf("[GIET ERROR] in _timer_stop()\n");
128        _exit();
129    }
130
131    unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE +
132                                  (cluster_xy * PERI_CLUSTER_INCREMENT) );
133
134    timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0;
135
136#else
137    _printf("[GIET ERROR] _timer_stop() should not be called when NB_TIM_CHANNELS is 0\n");
138    _exit();
139#endif
140}
141
142//////////////////////////////////////////////////////////////////////////////
143// This function acknowlegge a timer interrupt in the vci_timer 
144// component by writing in the proper register.
145// It can be used by both the isr_switch() for a "system" timer,
146// or by the _isr_timer() for an "user" timer.
147// Returns 0 if success, > 0 if error.
148//////////////////////////////////////////////////////////////////////////////
149void _timer_reset_irq( unsigned int cluster_xy, 
150                       unsigned int local_id ) 
151{
152#if NB_TIM_CHANNELS
153
154    // parameters checking
155    unsigned int x = cluster_xy >> Y_WIDTH;
156    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
157    if ( (x >= X_SIZE) || (y >= Y_SIZE) || (local_id >= NB_TIM_CHANNELS) )
158    {
159        _printf("[GIET ERROR] in _timer_reset_irq()\n");
160        _exit();
161    }
162
163    unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE +
164                                  (cluster_xy * PERI_CLUSTER_INCREMENT) );
165
166    timer_address[local_id * TIMER_SPAN + TIMER_RESETIRQ] = 0;
167
168#else
169    _printf("[GIET ERROR] _timer_reset_irq() should not be called when NB_TIM_CHANNELS is 0\n");
170    _exit();
171#endif
172}
173
174/////////////////////////////////////////////////////////////////////////////
175// This function resets the timer counter. To do so, we re-write the period
176// in the proper register, what causes the count to restart.
177// The period value is read from the same (TIMER_PERIOD) register,
178// this is why in appearance we do nothing useful (read a value
179// from a register and write this value in the same register)
180// This function is called during a context switch (user or preemptive)
181//////////////////////////////////////////////////////////////////////i//////
182void _timer_reset_cpt( unsigned int cluster_xy, 
183                       unsigned int local_id) 
184{
185#if NB_TIM_CHANNELS
186
187    // parameters checking
188    unsigned int x = cluster_xy >> Y_WIDTH;
189    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
190    if ( (x >= X_SIZE) || (y >= Y_SIZE) || (local_id >= NB_TIM_CHANNELS) )
191    {
192        _printf("[GIET ERROR in _timer_reset_cpt()\n");
193        _exit();
194    }
195
196    // We suppose that the TIMER_MODE register value is 0x3
197    unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE +
198                                  (cluster_xy * PERI_CLUSTER_INCREMENT) );
199
200    unsigned int period = timer_address[local_id * TIMER_SPAN + TIMER_PERIOD];
201    timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period;
202
203#else
204    _printf("[GIET ERROR] _timer_reset_cpt should not be called when NB_TIM_CHANNELS is 0\n");
205    _exit();
206#endif
207}
208
209///////////////////////////////////////////////////////////////////////////////////
210// This ISR handles the IRQs generated by the "user" timers that are
211// replicated in all clusters.
212// The IRQs generated by the "system" timers should be handled by _isr_switch().
213// It can be a HWI or a PTI.
214// The channel argument is the user timer local index.
215//     timer_global_id = cluster_id*(NB_TIM_CHANNELS) + channel
216// The ISR acknowledges the IRQ and registers the event in the proper entry
217// of the _user_timer_event[] array, and a log message is displayed on TTY0.
218///////////////////////////////////////////////////////////////////////////////////
219void _timer_isr( unsigned int irq_type,   // HWI / PTI
220                 unsigned int irq_id,     // index returned by XCU
221                 unsigned int channel )   // user timer index
222{
223#if NB_TIM_CHANNELS
224
225    unsigned int cluster_xy = _get_procid() / NB_PROCS_MAX;
226
227    // acknowledge IRQ depending on type
228    if   ( irq_type == IRQ_TYPE_HWI )  _timer_reset_irq( cluster_xy, channel );
229    else                               _xcu_timer_reset_irq( cluster_xy, irq_id );
230
231    // register the event
232    _user_timer_event[cluster_xy * NB_TIM_CHANNELS + channel] = 1;
233
234    // display a message on TTY 0
235    _printf("\n[GIET WARNING] User Timer IRQ at cycle %d / cluster = %x / channel = %d\n",
236            _get_proctime(), cluster_xy, channel );
237
238#else
239    _printf("[GIET ERROR] _timer_isr() should not be called when NB_TIM_CHANNELS == 0\n");
240    _exit();
241#endif
242}
243
244
245
246// Local Variables:
247// tab-width: 4
248// c-basic-offset: 4
249// c-file-offsets:((innamespace . 0)(inline-open . 0))
250// indent-tabs-mode: nil
251// End:
252// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
253
Note: See TracBrowser for help on using the repository browser.