forked from lambdaconcept/lambdasoc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
timer.py
183 lines (148 loc) · 5.89 KB
/
timer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
from nmigen import *
from . import Peripheral
from ..event import *
from ..register import *
__all__ = ["Timer"]
class Timer(Peripheral, Elaboratable):
"""Timer peripheral.
A general purpose down-counting timer peripheral."""
creator_id = StaticHalfWord(0x0, 0x1248)
"""Creator id for Scott Shawcroft: 0x1248"""
creation_id = StaticHalfWord(0x2, 0x0000)
"""Creation id: 0x0000"""
reload_ = VariableWidth(0x4)
"""Reload value of counter. When `ctr` reaches 0, it is automatically reloaded with this value.
If the written value is larger than the timer width, only the bits within the timer's range
will be kept."""
enable = Bit(0x8, 0x0)
"""Counter enable."""
value = VariableWidth(0xc)
"""Counter value."""
event_enable = AggregateEventEnable(0x10)
"""Enables interrupt generation out of the peripheral."""
event_status = AggregateEventStatus(0x14)
"""Aggregate event status, write 0 to any bit to turn the interrupt off."""
width = Config(0x18, "_width")
"""Configured width of the timer. Read-only"""
zero = Event(0x14, 0x0, mode="rise")
"""Counter value reached 0. Event bit 0."""
aggregate_event = AggregateEvent()
"""High signal when any individual event is active and enabled."""
def __init__(self, memory_window, *, width=None):
"""Parameters
----------
width : int
Counter width.
Attributes
----------
bus : :class:`nmigen_soc.wishbone.Interface`
Wishbone bus interface.
irq : :class:`IRQLine`
Interrupt request.
"""
super().__init__(memory_window)
if isinstance(memory_window, Record):
if not isinstance(memory_window, csr.Interface):
raise ValueError("Timer must connect to csr.Interface")
if not isinstance(width, int) or width < 0:
raise ValueError("Counter width must be a non-negative integer, not {!r}"
.format(width))
if width > 32:
raise ValueError("Counter width cannot be greater than 32 (was: {})"
.format(width))
self._width = width
# bank = self.csr_bank()
# self._reload = bank.csr(width, "rw")
# self._en = bank.csr( 1, "rw")
# self._ctr = bank.csr(width, "rw")
# self._zero_ev = self.event(mode="rise")
# self._bridge = self.bridge(data_width=32, granularity=8, alignment=2)
# self.bus = self._bridge.bus
#self.irq = self._bridge.irq
def elaborate(self, platform):
m = Module()
with m.If(self.enable.r_data):
with m.If(self.value.r_data == 0):
m.d.comb += self.zero.eq(1)
m.d.sync += self.value.r_data.eq(self.reload_.r_data)
with m.Else():
m.d.sync += self.value.r_data.eq(self.value.r_data - 1)
with m.If(self.reload_.w_stb):
m.d.sync += self.reload_.r_data.eq(self.reload_.w_data)
with m.If(self.enable.w_stb):
m.d.sync += self.enable.r_data.eq(self.enable.w_data)
with m.If(self.value.w_stb):
m.d.sync += self.value.r_data.eq(self.value.w_data)
m.submodules.peripheral = super().elaborate(platform)
return m
if __name__ == "__main__":
from nmigen.back.pysim import Simulator
from nmigen.back import verilog
bus = csr.Interface(addr_width=14,
data_width=8,
name="csr")
t = Timer(bus, width=4)
class SimulatorBus:
def __init__(self, sim, bus):
self._sim = sim
self._bus = bus
self._read_address = None
self._read_data = None
self._write_address = None
self._write_data = None
def actions(self):
while True:
if self._read_address is not None:
yield self._bus.addr.eq(self._read_address)
yield self._bus.r_stb.eq(1)
yield
yield self._bus.r_stb.eq(0)
yield
self._read_data = yield self._bus.r_data
self._read_address = None
elif self._write_address is not None and self._write_data is not None:
yield bus.addr.eq(self._write_address)
yield bus.w_data.eq(self._write_data)
yield bus.w_stb.eq(1)
yield
yield bus.w_stb.eq(0)
yield
yield
self._write_address = None
self._write_data = None
else:
yield
def __getitem__(self, index):
#print("get", index, sim, bus)
self._read_address = index
while self._read_data is None:
self._sim.advance()
data = self._read_data
self._read_data = None
return data
def __setitem__(self, index, value):
print("set", index, sim, bus)
self._write_address = index
self._write_data = value
while self._write_data is not None:
self._sim.advance()
sim = Simulator(t)
sbus = SimulatorBus(sim, bus)
sim.add_clock(1e-6)
sim.add_sync_process(sbus.actions)
timer0 = Timer(sbus)
with sim.write_vcd("timer.vcd"):
print(timer0.width) # Should be 2
timer0.reload_ = 0xf
timer0.value = 0xe
print(timer0.enable) # Should be False
timer0.enable = True
for _ in range(50):
sim.advance()
print(timer0.enable)
print(timer0.value)
# wait 5 cycles
print(timer0.zero)
print(timer0.value)
with open("timer.v", "w") as f:
f.write(verilog.convert(t))