cded5ae29f23c6e6784b198d525e2474115d9c11
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, soc_bus_data_width
=32):
170 aligned_paging
= paging
//(soc_bus_data_width
//8)
174 csr
.GenericBank
.__init
__(self
, description
, len(self
.bus
.dat_w
))
177 self
.comb
+= sel
.eq(self
.bus
.adr
[log2_int(aligned_paging
):] == address
)
179 for i
, c
in enumerate(self
.simple_csrs
):
181 c
.r
.eq(self
.bus
.dat_w
[:c
.size
]),
184 (self
.bus
.adr
[:self
.decode_bits
] == i
)),
187 (self
.bus
.adr
[:self
.decode_bits
] == i
)),
190 brcases
= dict((i
, self
.bus
.dat_r
.eq(c
.w
)) for i
, c
in enumerate(self
.simple_csrs
))
192 self
.bus
.dat_r
.eq(0),
193 If(sel
, Case(self
.bus
.adr
[:self
.decode_bits
], brcases
))
197 # address_map(name, memory) returns the CSR offset at which to map
198 # the CSR object (register bank or memory).
199 # If memory=None, the object is the register bank of object source.name.
200 # Otherwise, it is a memory object belonging to source.name.
201 # address_map is called exactly once for each object at each call to
202 # scan(), so it can have side effects.
203 class CSRBankArray(Module
):
204 def __init__(self
, source
, address_map
, *ifargs
, paging
=0x800, soc_bus_data_width
=32, **ifkwargs
):
206 self
.address_map
= address_map
208 self
.soc_bus_data_width
= soc_bus_data_width
209 self
.scan(ifargs
, ifkwargs
)
211 def scan(self
, ifargs
, ifkwargs
):
215 for name
, obj
in xdir(self
.source
, True):
216 if hasattr(obj
, "get_csrs"):
217 csrs
= obj
.get_csrs()
220 if hasattr(obj
, "get_memories"):
221 memories
= obj
.get_memories()
222 for memory
in memories
:
223 if isinstance(memory
, tuple):
224 read_only
, memory
= memory
227 mapaddr
= self
.address_map(name
, memory
)
230 sram_bus
= Interface(*ifargs
, **ifkwargs
)
231 mmap
= SRAM(memory
, mapaddr
,
232 read_only
= read_only
,
234 paging
= self
.paging
)
235 self
.submodules
+= mmap
236 csrs
+= mmap
.get_csrs()
237 self
.srams
.append((name
, memory
, mapaddr
, mmap
))
238 if hasattr(obj
, "get_constants"):
239 for constant
in obj
.get_constants():
240 self
.constants
.append((name
, constant
))
242 mapaddr
= self
.address_map(name
, None)
245 bank_bus
= Interface(*ifargs
, **ifkwargs
)
246 rmap
= CSRBank(csrs
, mapaddr
,
248 paging
= self
.paging
,
249 soc_bus_data_width
= self
.soc_bus_data_width
)
250 self
.submodules
+= rmap
251 self
.banks
.append((name
, csrs
, mapaddr
, rmap
))
254 return [rmap
for name
, csrs
, mapaddr
, rmap
in self
.banks
]
257 return [mmap
for name
, memory
, mapaddr
, mmap
in self
.srams
]
260 return [i
.bus
for i
in self
.get_rmaps() + self
.get_mmaps()]