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

Last change on this file since 434 was 426, checked in by alain, 10 years ago

Introducing fixed format (X_WIDTH / Y_WIDTH / P_WIDTH ) for processor index.

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.
[320]21//
[258]22// The virtual base address of the segment associated to a channel is:
[333]23//     SEG_TIM_BASE + cluster_xy * PERI_CLUSTER_INCREMENT + TIMER_SPAN * timer_id
[258]24//
[333]25// The SEG_TIM_BASE and PERI_CLUSTER_INCREMENT must be defined in hard_config.h.
[258]26/////////////////////////////////////////////////////////////////////////////////////
27
28#include <giet_config.h>
29#include <tim_driver.h>
[295]30#include <xcu_driver.h>
31#include <tty_driver.h>
[258]32#include <utils.h>
33
[320]34#if !defined(SEG_TIM_BASE)
35# error: You must define SEG_TIM_BASE in the hard_config.h file
36#endif
37
[333]38#if !defined(PERI_CLUSTER_INCREMENT)
39# error: You must define PERI_CLUSTER_INCREMENT in the hard_config.h file
[320]40#endif
41
[263]42#if !defined(X_SIZE)
43# error: You must define X_SIZE in the hard_config.h file
[258]44#endif
45
[263]46#if !defined(Y_SIZE)
47# error: You must define X_SIZE in the hard_config.h file
[258]48#endif
49
[263]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
[258]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)
[295]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 };
[258]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.
[295]84///////////////////////////////////////////////////////////////////////////////////
85void _timer_start( unsigned int cluster_xy, 
86                   unsigned int local_id, 
87                   unsigned int period) 
[258]88{
[295]89#if NB_TIM_CHANNELS
90
[258]91    // parameters checking
[263]92    unsigned int x = cluster_xy >> Y_WIDTH;
93    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
[295]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    }
[258]99
[320]100    unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE +
[333]101                                  (cluster_xy * PERI_CLUSTER_INCREMENT) );
[258]102
103    timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period;
104    timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0x3;
[295]105
106#else
107    _printf("[GIET ERROR] _timer_start() should not be called when NB_TIM_CHANNELS is 0\n");
108    _exit();
109#endif
[258]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//////////////////////////////////////////////////////////////////////////////
[295]117void _timer_stop( unsigned int cluster_xy, 
118                  unsigned int local_id) 
[258]119{
[295]120#if NB_TIM_CHANNELS
121
[258]122    // parameters checking
[263]123    unsigned int x = cluster_xy >> Y_WIDTH;
124    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
[295]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    }
[258]130
[320]131    unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE +
[333]132                                  (cluster_xy * PERI_CLUSTER_INCREMENT) );
[258]133
134    timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0;
[295]135
136#else
137    _printf("[GIET ERROR] _timer_stop() should not be called when NB_TIM_CHANNELS is 0\n");
138    _exit();
139#endif
[258]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//////////////////////////////////////////////////////////////////////////////
[295]149void _timer_reset_irq( unsigned int cluster_xy, 
150                       unsigned int local_id ) 
[258]151{
[295]152#if NB_TIM_CHANNELS
153
[258]154    // parameters checking
[263]155    unsigned int x = cluster_xy >> Y_WIDTH;
156    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
[295]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    }
[258]162
[320]163    unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE +
[333]164                                  (cluster_xy * PERI_CLUSTER_INCREMENT) );
[258]165
166    timer_address[local_id * TIMER_SPAN + TIMER_RESETIRQ] = 0;
[295]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
[258]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//////
[295]182void _timer_reset_cpt( unsigned int cluster_xy, 
183                       unsigned int local_id) 
[258]184{
[295]185#if NB_TIM_CHANNELS
186
[258]187    // parameters checking
[263]188    unsigned int x = cluster_xy >> Y_WIDTH;
189    unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1);
[295]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    }
[258]195
196    // We suppose that the TIMER_MODE register value is 0x3
[320]197    unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE +
[333]198                                  (cluster_xy * PERI_CLUSTER_INCREMENT) );
[258]199
200    unsigned int period = timer_address[local_id * TIMER_SPAN + TIMER_PERIOD];
201    timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period;
[295]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
[258]207}
208
[295]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
[258]224
[426]225    unsigned int cluster_xy = _get_procid() >> P_WIDTH;
[295]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
[258]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.