periph.timer: add TimerPeripheral
[lambdasoc.git] / lambdasoc / periph / timer.py
1 from nmigen import *
2
3 from . import Peripheral
4
5
6 __all__ = ["TimerPeripheral"]
7
8
9 class TimerPeripheral(Peripheral, Elaboratable):
10 """Timer peripheral.
11
12 A general purpose down-counting timer peripheral.
13
14 CSR registers
15 -------------
16 reload : read/write
17 Reload value of counter. When `ctr` reaches 0, it is automatically reloaded with this value.
18 en : read/write
19 Counter enable.
20 ctr : read/write
21 Counter value.
22
23 Events
24 ------
25 zero : edge-triggered (rising)
26 Counter value reached 0.
27
28 Parameters
29 ----------
30 width : int
31 Counter width.
32
33 Attributes
34 ----------
35 bus : :class:`nmigen_soc.wishbone.Interface`
36 Wishbone bus interface.
37 irq : :class:`IRQLine`
38 Interrupt request.
39 """
40 def __init__(self, width):
41 super().__init__()
42
43 if not isinstance(width, int) or width < 0:
44 raise ValueError("Counter width must be a non-negative integer, not {!r}"
45 .format(width))
46 if width > 32:
47 raise ValueError("Counter width cannot be greater than 32 (was: {})"
48 .format(width))
49 self.width = width
50
51 bank = self.csr_bank()
52 self._reload = bank.csr(width, "rw")
53 self._en = bank.csr( 1, "rw")
54 self._ctr = bank.csr(width, "rw")
55
56 self._zero_ev = self.event(mode="rise")
57
58 self._bridge = self.bridge(data_width=32, granularity=8, alignment=2)
59 self.bus = self._bridge.bus
60 self.irq = self._bridge.irq
61
62 def elaborate(self, platform):
63 m = Module()
64 m.submodules.bridge = self._bridge
65
66 with m.If(self._en.r_data):
67 with m.If(self._ctr.r_data == 0):
68 m.d.comb += self._zero_ev.stb.eq(1)
69 m.d.sync += self._ctr.r_data.eq(self._reload.r_data)
70 with m.Else():
71 m.d.sync += self._ctr.r_data.eq(self._ctr.r_data - 1)
72
73 with m.If(self._reload.w_stb):
74 m.d.sync += self._reload.r_data.eq(self._reload.w_data)
75 with m.If(self._en.w_stb):
76 m.d.sync += self._en.r_data.eq(self._en.w_data)
77 with m.If(self._ctr.w_stb):
78 m.d.sync += self._ctr.r_data.eq(self._ctr.w_data)
79
80 return m