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

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

Introducing a major release, to suppoort the tsar_generic_leti platform
and the various (external or internal) peripherals configurations.
The map.xml format has been modified, in order to support the new
vci_iopic componentand a new policy for peripherals initialisation.
The IRQs are nom described in the XICU and IOPIC components
(and not anymore in the processors).
To enforce this major change, the map.xml file signature changed:
The signature value must be: 0xDACE2014

This new release has been tested on the tsar_generic_leti platform
for the following mappings:

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