-
Notifications
You must be signed in to change notification settings - Fork 209
/
description.py
157 lines (142 loc) · 4.7 KB
/
description.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
from migen.fhdl.structure import *
from migen.fhdl.specials import Memory
from migen.fhdl.tracer import get_obj_var_name
class _Register(HUID):
def __init__(self, name):
HUID.__init__(self)
self.name = get_obj_var_name(name)
if self.name is None:
raise ValueError("Cannot extract register name from code, need to specify.")
if len(self.name) > 2 and self.name[:2] == "r_":
self.name = self.name[2:]
class RegisterRaw(_Register):
def __init__(self, size=1, name=None):
_Register.__init__(self, name)
self.size = size
self.re = Signal()
self.r = Signal(self.size)
self.w = Signal(self.size)
(READ_ONLY, WRITE_ONLY, READ_WRITE) = range(3)
class Field:
def __init__(self, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0, atomic_write=False, name=None):
self.name = get_obj_var_name(name)
if self.name is None:
raise ValueError("Cannot extract field name from code, need to specify.")
self.size = size
self.access_bus = access_bus
self.access_dev = access_dev
self.storage = Signal(self.size, reset=reset)
self.atomic_write = atomic_write
if self.access_bus == READ_ONLY and self.access_dev == WRITE_ONLY:
self.w = Signal(self.size)
else:
if self.access_dev == READ_ONLY or self.access_dev == READ_WRITE:
self.r = Signal(self.size, reset=reset)
if self.access_dev == WRITE_ONLY or self.access_dev == READ_WRITE:
self.w = Signal(self.size)
self.we = Signal()
class RegisterFields(_Register):
def __init__(self, *fields, name=None):
_Register.__init__(self, name)
self.fields = fields
class RegisterField(RegisterFields):
def __init__(self, size=1, access_bus=READ_WRITE, access_dev=READ_ONLY, reset=0, atomic_write=False, name=None):
self.field = Field(size, access_bus, access_dev, reset, atomic_write, name="")
RegisterFields.__init__(self, self.field, name=name)
def regprefix(prefix, registers):
for register in registers:
register.name = prefix + register.name
def memprefix(prefix, memories):
for memory in memories:
memory.name_override = prefix + memory.name_override
class AutoReg:
def get_memories(self):
r = []
for k, v in self.__dict__.items():
if isinstance(v, Memory):
r.append(v)
elif hasattr(v, "get_memories") and callable(v.get_memories):
memories = v.get_memories()
memprefix(k + "_", memories)
r += memories
return sorted(r, key=lambda x: x.huid)
def get_registers(self):
r = []
for k, v in self.__dict__.items():
if isinstance(v, _Register):
r.append(v)
elif hasattr(v, "get_registers") and callable(v.get_registers):
registers = v.get_registers()
regprefix(k + "_", registers)
r += registers
return sorted(r, key=lambda x: x.huid)
(ALIAS_NON_ATOMIC, ALIAS_ATOMIC_HOLD, ALIAS_ATOMIC_COMMIT) = range(3)
class FieldAlias:
def __init__(self, mode, f, start, end, commit_list):
self.mode = mode
self.size = end - start
self.access_bus = f.access_bus
self.access_dev = f.access_dev
if mode == ALIAS_ATOMIC_HOLD:
self.storage = Signal(end-start, name="atomic_hold")
self.commit_to = f.storage[start:end]
else:
self.storage = f.storage[start:end]
if mode == ALIAS_ATOMIC_COMMIT:
self.commit_list = commit_list
else:
self.commit_list = []
# device access is through the original field
def expand_description(description, busword):
d = []
for reg in description:
if isinstance(reg, RegisterRaw):
if reg.size > busword:
raise ValueError("Raw register larger than a bus word")
d.append(reg)
elif isinstance(reg, RegisterFields):
f = []
offset = 0
totalsize = 0
for field in reg.fields:
offset += field.size
totalsize += field.size
if offset > busword:
# add padding
padding = busword - (totalsize % busword)
if padding != busword:
totalsize += padding
offset += padding
top = field.size
commit_list = []
while offset > busword:
if field.atomic_write:
if offset - busword > busword:
mode = ALIAS_ATOMIC_HOLD
else:
# last iteration
mode = ALIAS_ATOMIC_COMMIT
else:
mode = ALIAS_NON_ATOMIC
slice1 = busword - offset + top
slice2 = min(offset - busword, busword)
if slice1:
alias = FieldAlias(mode, field, top - slice1, top, commit_list)
f.append(alias)
if mode == ALIAS_ATOMIC_HOLD:
commit_list.append(alias)
top -= slice1
d.append(RegisterFields(*f, name=reg.name))
alias = FieldAlias(mode, field, top - slice2, top, commit_list)
f = [alias]
if mode == ALIAS_ATOMIC_HOLD:
commit_list.append(alias)
top -= slice2
offset -= busword
else:
f.append(field)
if f:
d.append(RegisterFields(*f, name=reg.name))
else:
raise TypeError
return d