diff options
Diffstat (limited to 'docs/devel/clocks.rst')
-rw-r--r-- | docs/devel/clocks.rst | 71 |
1 files changed, 63 insertions, 8 deletions
diff --git a/docs/devel/clocks.rst b/docs/devel/clocks.rst index c54bbb8240..956bd147ea 100644 --- a/docs/devel/clocks.rst +++ b/docs/devel/clocks.rst @@ -80,11 +80,12 @@ Adding clocks to a device must be done during the init method of the Device instance. To add an input clock to a device, the function ``qdev_init_clock_in()`` -must be used. It takes the name, a callback and an opaque parameter -for the callback (this will be explained in a following section). +must be used. It takes the name, a callback, an opaque parameter +for the callback and a mask of events when the callback should be +called (this will be explained in a following section). Output is simpler; only the name is required. Typically:: - qdev_init_clock_in(DEVICE(dev), "clk_in", clk_in_callback, dev); + qdev_init_clock_in(DEVICE(dev), "clk_in", clk_in_callback, dev, ClockUpdate); qdev_init_clock_out(DEVICE(dev), "clk_out"); Both functions return the created Clock pointer, which should be saved in the @@ -113,7 +114,7 @@ output. * callback for the input clock (see "Callback on input clock * change" section below for more information). */ - static void clk_in_callback(void *opaque); + static void clk_in_callback(void *opaque, ClockEvent event); /* * static array describing clocks: @@ -124,7 +125,7 @@ output. * the clk_out field of a MyDeviceState structure. */ static const ClockPortInitArray mydev_clocks = { - QDEV_CLOCK_IN(MyDeviceState, clk_in, clk_in_callback), + QDEV_CLOCK_IN(MyDeviceState, clk_in, clk_in_callback, ClockUpdate), QDEV_CLOCK_OUT(MyDeviceState, clk_out), QDEV_CLOCK_END }; @@ -153,6 +154,47 @@ nothing else to do. This value will be propagated to other clocks when connecting the clocks together and devices will fetch the right value during the first reset. +Clock callbacks +--------------- + +You can give a clock a callback function in several ways: + + * by passing it as an argument to ``qdev_init_clock_in()`` + * as an argument to the ``QDEV_CLOCK_IN()`` macro initializing an + array to be passed to ``qdev_init_clocks()`` + * by directly calling the ``clock_set_callback()`` function + +The callback function must be of this type: + +.. code-block:: c + + typedef void ClockCallback(void *opaque, ClockEvent event); + +The ``opaque`` argument is the pointer passed to ``qdev_init_clock_in()`` +or ``clock_set_callback()``; for ``qdev_init_clocks()`` it is the +``dev`` device pointer. + +The ``event`` argument specifies why the callback has been called. +When you register the callback you specify a mask of ClockEvent values +that you are interested in. The callback will only be called for those +events. + +The events currently supported are: + + * ``ClockPreUpdate`` : called when the input clock's period is about to + update. This is useful if the device needs to do some action for + which it needs to know the old value of the clock period. During + this callback, Clock API functions like ``clock_get()`` or + ``clock_ticks_to_ns()`` will use the old period. + * ``ClockUpdate`` : called after the input clock's period has changed. + During this callback, Clock API functions like ``clock_ticks_to_ns()`` + will use the new period. + +Note that a clock only has one callback: it is not possible to register +different functions for different events. You must register a single +callback which listens for all of the events you are interested in, +and use the ``event`` argument to identify which event has happened. + Retrieving clocks from a device ------------------------------- @@ -231,7 +273,7 @@ object during device instance init. For example: .. code-block:: c clk = qdev_init_clock_in(DEVICE(dev), "clk-in", clk_in_callback, - dev); + dev, ClockUpdate); /* set initial value to 10ns / 100MHz */ clock_set_ns(clk, 10); @@ -267,11 +309,12 @@ next lowest integer. This implies some inaccuracy due to the rounding, so be cautious about using it in calculations. It is also possible to register a callback on clock frequency changes. -Here is an example: +Here is an example, which assumes that ``clock_callback`` has been +specified as the callback for the ``ClockUpdate`` event: .. code-block:: c - void clock_callback(void *opaque) { + void clock_callback(void *opaque, ClockEvent event) { MyDeviceState *s = (MyDeviceState *) opaque; /* * 'opaque' is the argument passed to qdev_init_clock_in(); @@ -317,6 +360,18 @@ rather than simply passing it to a QEMUTimer function like ``timer_mod_ns()`` then you should be careful to avoid overflow in those calculations, of course.) +Obtaining tick counts +--------------------- + +For calculations where you need to know the number of ticks in +a given duration, use ``clock_ns_to_ticks()``. This function handles +possible non-whole-number-of-nanoseconds periods and avoids +potential rounding errors. It will return '0' if the clock is stopped +(i.e. it has period zero). If the inputs imply a tick count that +overflows a 64-bit value (a very long duration for a clock with a +very short period) the output value is truncated, so effectively +the 64-bit output wraps around. + Changing a clock period ----------------------- |