1 # This file is Copyright (c) 2015 Sebastien Bourdeauducq <sb@m-labs.hk>
2 # This file is Copyright (c) 2015-2018 Florent Kermarrec <florent@enjoy-digital.fr>
3 # This file is Copyright (c) 2016-2019 Tim 'mithro' Ansell <me@mith.ro>
10 The CSR-2 bus is a low-bandwidth, resource-sensitive bus designed for accessing
11 the configuration and status registers of cores from software.
14 from functools
import reduce
15 from operator
import or_
18 from migen
.genlib
.record
import *
19 from migen
.genlib
.misc
import chooser
20 from migen
.util
.misc
import xdir
22 from litex
.soc
.interconnect
import csr
23 from litex
.soc
.interconnect
.csr
import CSRStorage
25 # CSR Definition -----------------------------------------------------------------------------------
28 ("adr", "address_width", DIR_M_TO_S
),
29 ("we", 1, DIR_M_TO_S
),
30 ("dat_w", "data_width", DIR_M_TO_S
),
31 ("dat_r", "data_width", DIR_S_TO_M
)
35 class Interface(Record
):
36 def __init__(self
, data_width
=8, address_width
=14, alignment
=32):
37 self
.data_width
= data_width
38 self
.address_width
= address_width
39 self
.alignment
= alignment
40 Record
.__init
__(self
, set_layout_parameters(_layout
,
41 data_width
= data_width
,
42 address_width
= address_width
))
43 self
.adr
.reset_less
= True
44 self
.dat_w
.reset_less
= True
45 self
.dat_r
.reset_less
= True
48 def like(self
, other
):
49 return Interface(len(other
.dat_w
),
52 def write(self
, adr
, dat
):
53 yield self
.adr
.eq(adr
)
54 yield self
.dat_w
.eq(dat
)
60 yield self
.adr
.eq(adr
)
63 return (yield self
.dat_r
)
65 # CSR Interconnect ---------------------------------------------------------------------------------
67 class Interconnect(Module
):
68 def __init__(self
, master
, slaves
):
69 self
.comb
+= master
.connect(*slaves
)
72 class InterconnectShared(Module
):
73 def __init__(self
, masters
, slaves
):
74 intermediate
= Interface
.like(masters
[0])
76 intermediate
.adr
.eq(reduce(or_
, [masters
[i
].adr
for i
in range(len(masters
))])),
77 intermediate
.we
.eq(reduce(or_
, [masters
[i
].we
for i
in range(len(masters
))])),
78 intermediate
.dat_w
.eq(reduce(or_
, [masters
[i
].dat_w
for i
in range(len(masters
))]))
80 for i
in range(len(masters
)):
81 self
.comb
+= masters
[i
].dat_r
.eq(intermediate
.dat_r
)
82 self
.comb
+= intermediate
.connect(*slaves
)
84 # CSR SRAM -----------------------------------------------------------------------------------------
87 def __init__(self
, mem_or_size
, address
, read_only
=None, init
=None, bus
=None, paging
=0x800, soc_bus_data_width
=32):
91 aligned_paging
= paging
//(soc_bus_data_width
//8)
92 data_width
= len(self
.bus
.dat_w
)
93 if isinstance(mem_or_size
, Memory
):
96 mem
= Memory(data_width
, mem_or_size
//(data_width
//8), init
=init
)
97 mem_size
= int(mem
.width
*mem
.depth
/8)
98 csrw_per_memw
= (mem
.width
+ data_width
- 1)//data_width
99 word_bits
= log2_int(csrw_per_memw
)
100 page_bits
= log2_int((mem
.depth
*csrw_per_memw
+ aligned_paging
- 1)//aligned_paging
, False)
102 self
._page
= CSRStorage(page_bits
, name
=mem
.name_override
+ "_page")
103 print("WARNING: SRAM CSR memory will require paged access.")
106 if read_only
is None:
107 if hasattr(mem
, "bus_read_only"):
108 read_only
= mem
.bus_read_only
114 port
= mem
.get_port(write_capable
=not read_only
)
115 self
.specials
+= mem
, port
119 self
.sync
+= sel_r
.eq(sel
)
120 self
.comb
+= sel
.eq(self
.bus
.adr
[log2_int(aligned_paging
):] == address
)
123 word_index
= Signal(word_bits
, reset_less
=True)
124 word_expanded
= Signal(csrw_per_memw
*data_width
)
125 self
.sync
+= word_index
.eq(self
.bus
.adr
[:word_bits
])
127 word_expanded
.eq(port
.dat_r
),
129 chooser(word_expanded
, word_index
, self
.bus
.dat_r
, n
=csrw_per_memw
, reverse
=True)
134 for i
in range(csrw_per_memw
-1):
135 wreg
= Signal(data_width
, reset_less
=True)
136 self
.sync
+= If(sel
& self
.bus
.we
& (self
.bus
.adr
[:word_bits
] == i
), wreg
.eq(self
.bus
.dat_w
))
138 memword_chunks
= [self
.bus
.dat_w
] + list(reversed(wregs
))
140 port
.we
.eq(sel
& self
.bus
.we
& (self
.bus
.adr
[:word_bits
] == csrw_per_memw
- 1)),
141 port
.dat_w
.eq(Cat(*memword_chunks
))
144 self
.comb
+= If(sel_r
, self
.bus
.dat_r
.eq(port
.dat_r
))
147 port
.we
.eq(sel
& self
.bus
.we
),
148 port
.dat_w
.eq(self
.bus
.dat_w
)
151 if self
._page
is None:
152 self
.comb
+= port
.adr
.eq(self
.bus
.adr
[word_bits
:word_bits
+len(port
.adr
)])
154 pv
= self
._page
.storage
155 self
.comb
+= port
.adr
.eq(Cat(self
.bus
.adr
[word_bits
:word_bits
+len(port
.adr
)-len(pv
)], pv
))
158 if self
._page
is None:
163 # CSR Bank -----------------------------------------------------------------------------------------
165 class CSRBank(csr
.GenericBank
):
166 def __init__(self
, description
, address
=0, bus
=None, paging
=0x800, ordering
="big", soc_bus_data_width
=32):
170 aligned_paging
= paging
//(soc_bus_data_width
//8)
174 csr
.GenericBank
.__init
__(self
,
175 description
= description
,
176 busword
= len(self
.bus
.dat_w
),
181 self
.comb
+= sel
.eq(self
.bus
.adr
[log2_int(aligned_paging
):] == address
)
183 for i
, c
in enumerate(self
.simple_csrs
):
185 c
.r
.eq(self
.bus
.dat_w
[:c
.size
]),
188 (self
.bus
.adr
[:self
.decode_bits
] == i
)),
191 (self
.bus
.adr
[:self
.decode_bits
] == i
)),
194 brcases
= dict((i
, self
.bus
.dat_r
.eq(c
.w
)) for i
, c
in enumerate(self
.simple_csrs
))
196 self
.bus
.dat_r
.eq(0),
197 If(sel
, Case(self
.bus
.adr
[:self
.decode_bits
], brcases
))
201 # address_map(name, memory) returns the CSR offset at which to map
202 # the CSR object (register bank or memory).
203 # If memory=None, the object is the register bank of object source.name.
204 # Otherwise, it is a memory object belonging to source.name.
205 # address_map is called exactly once for each object at each call to
206 # scan(), so it can have side effects.
207 class CSRBankArray(Module
):
208 def __init__(self
, source
, address_map
, *ifargs
, paging
=0x800, ordering
="big", soc_bus_data_width
=32, **ifkwargs
):
210 self
.address_map
= address_map
212 self
.ordering
= ordering
213 self
.soc_bus_data_width
= soc_bus_data_width
214 self
.scan(ifargs
, ifkwargs
)
216 def scan(self
, ifargs
, ifkwargs
):
220 for name
, obj
in xdir(self
.source
, True):
221 if hasattr(obj
, "get_csrs"):
222 csrs
= obj
.get_csrs()
225 if hasattr(obj
, "get_memories"):
226 memories
= obj
.get_memories()
227 for memory
in memories
:
228 if isinstance(memory
, tuple):
229 read_only
, memory
= memory
232 mapaddr
= self
.address_map(name
, memory
)
235 sram_bus
= Interface(*ifargs
, **ifkwargs
)
236 mmap
= SRAM(memory
, mapaddr
,
237 read_only
= read_only
,
239 paging
= self
.paging
)
240 self
.submodules
+= mmap
241 csrs
+= mmap
.get_csrs()
242 self
.srams
.append((name
, memory
, mapaddr
, mmap
))
243 if hasattr(obj
, "get_constants"):
244 for constant
in obj
.get_constants():
245 self
.constants
.append((name
, constant
))
247 mapaddr
= self
.address_map(name
, None)
250 bank_bus
= Interface(*ifargs
, **ifkwargs
)
251 rmap
= CSRBank(csrs
, mapaddr
,
253 paging
= self
.paging
,
254 ordering
= self
.ordering
,
255 soc_bus_data_width
= self
.soc_bus_data_width
)
256 self
.submodules
+= rmap
257 self
.banks
.append((name
, csrs
, mapaddr
, rmap
))
260 return [rmap
for name
, csrs
, mapaddr
, rmap
in self
.banks
]
263 return [mmap
for name
, memory
, mapaddr
, mmap
in self
.srams
]
266 return [i
.bus
for i
in self
.get_rmaps() + self
.get_mmaps()]