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
27 ("adr", "address_width", DIR_M_TO_S
),
28 ("we", 1, DIR_M_TO_S
),
29 ("dat_w", "data_width", DIR_M_TO_S
),
30 ("dat_r", "data_width", DIR_S_TO_M
)
34 class Interface(Record
):
35 def __init__(self
, data_width
=8, address_width
=14, alignment
=32):
36 self
.alignment
= alignment
37 Record
.__init
__(self
, set_layout_parameters(_layout
,
38 data_width
=data_width
, address_width
=address_width
))
41 def like(self
, other
):
42 return Interface(len(other
.dat_w
),
45 def write(self
, adr
, dat
):
46 yield self
.adr
.eq(adr
)
47 yield self
.dat_w
.eq(dat
)
53 yield self
.adr
.eq(adr
)
56 return (yield self
.dat_r
)
59 class Interconnect(Module
):
60 def __init__(self
, master
, slaves
):
61 self
.comb
+= master
.connect(*slaves
)
64 class InterconnectShared(Module
):
65 def __init__(self
, masters
, slaves
):
66 intermediate
= Interface
.like(masters
[0])
68 intermediate
.adr
.eq(reduce(or_
, [masters
[i
].adr
for i
in range(len(masters
))])),
69 intermediate
.we
.eq(reduce(or_
, [masters
[i
].we
for i
in range(len(masters
))])),
70 intermediate
.dat_w
.eq(reduce(or_
, [masters
[i
].dat_w
for i
in range(len(masters
))]))
72 for i
in range(len(masters
)):
73 self
.comb
+= masters
[i
].dat_r
.eq(intermediate
.dat_r
)
74 self
.comb
+= intermediate
.connect(*slaves
)
78 def __init__(self
, mem_or_size
, address
, read_only
=None, init
=None, bus
=None):
82 data_width
= len(self
.bus
.dat_w
)
83 if isinstance(mem_or_size
, Memory
):
86 mem
= Memory(data_width
, mem_or_size
//(data_width
//8), init
=init
)
87 csrw_per_memw
= (mem
.width
+ data_width
- 1)//data_width
88 word_bits
= log2_int(csrw_per_memw
)
89 page_bits
= log2_int((mem
.depth
*csrw_per_memw
+ 511)//512, False)
91 self
._page
= CSRStorage(page_bits
, name
=mem
.name_override
+ "_page")
95 if hasattr(mem
, "bus_read_only"):
96 read_only
= mem
.bus_read_only
102 port
= mem
.get_port(write_capable
=not read_only
)
103 self
.specials
+= mem
, port
107 self
.sync
+= sel_r
.eq(sel
)
108 self
.comb
+= sel
.eq(self
.bus
.adr
[9:] == address
)
111 word_index
= Signal(word_bits
)
112 word_expanded
= Signal(csrw_per_memw
*data_width
)
113 self
.sync
+= word_index
.eq(self
.bus
.adr
[:word_bits
])
115 word_expanded
.eq(port
.dat_r
),
117 chooser(word_expanded
, word_index
, self
.bus
.dat_r
, n
=csrw_per_memw
, reverse
=True)
122 for i
in range(csrw_per_memw
-1):
123 wreg
= Signal(data_width
)
124 self
.sync
+= If(sel
& self
.bus
.we
& (self
.bus
.adr
[:word_bits
] == i
), wreg
.eq(self
.bus
.dat_w
))
126 memword_chunks
= [self
.bus
.dat_w
] + list(reversed(wregs
))
128 port
.we
.eq(sel
& self
.bus
.we
& (self
.bus
.adr
[:word_bits
] == csrw_per_memw
- 1)),
129 port
.dat_w
.eq(Cat(*memword_chunks
))
132 self
.comb
+= If(sel_r
, self
.bus
.dat_r
.eq(port
.dat_r
))
135 port
.we
.eq(sel
& self
.bus
.we
),
136 port
.dat_w
.eq(self
.bus
.dat_w
)
139 if self
._page
is None:
140 self
.comb
+= port
.adr
.eq(self
.bus
.adr
[word_bits
:word_bits
+len(port
.adr
)])
142 pv
= self
._page
.storage
143 self
.comb
+= port
.adr
.eq(Cat(self
.bus
.adr
[word_bits
:word_bits
+len(port
.adr
)-len(pv
)], pv
))
146 if self
._page
is None:
152 class CSRBank(csr
.GenericBank
):
153 def __init__(self
, description
, address
=0, bus
=None):
160 csr
.GenericBank
.__init
__(self
, description
, len(self
.bus
.dat_w
))
163 self
.comb
+= sel
.eq(self
.bus
.adr
[9:] == address
)
164 if bus
.alignment
== 64:
165 self
.comb
+= If(self
.bus
.adr
[0], sel
.eq(0))
167 adr_shift
= log2_int(bus
.alignment
//32)
169 for i
, c
in enumerate(self
.simple_csrs
):
171 c
.r
.eq(self
.bus
.dat_w
[:c
.size
]),
174 (self
.bus
.adr
[adr_shift
:adr_shift
+self
.decode_bits
] == i
))
177 brcases
= dict((i
, self
.bus
.dat_r
.eq(c
.w
)) for i
, c
in enumerate(self
.simple_csrs
))
179 self
.bus
.dat_r
.eq(0),
180 If(sel
, Case(self
.bus
.adr
[adr_shift
:adr_shift
+self
.decode_bits
], brcases
))
184 # address_map(name, memory) returns the CSR offset at which to map
185 # the CSR object (register bank or memory).
186 # If memory=None, the object is the register bank of object source.name.
187 # Otherwise, it is a memory object belonging to source.name.
188 # address_map is called exactly once for each object at each call to
189 # scan(), so it can have side effects.
190 class CSRBankArray(Module
):
191 def __init__(self
, source
, address_map
, *ifargs
, **ifkwargs
):
193 self
.address_map
= address_map
194 self
.scan(ifargs
, ifkwargs
)
196 def scan(self
, ifargs
, ifkwargs
):
200 for name
, obj
in xdir(self
.source
, True):
201 if hasattr(obj
, "get_csrs"):
202 csrs
= obj
.get_csrs()
205 if hasattr(obj
, "get_memories"):
206 memories
= obj
.get_memories()
207 for memory
in memories
:
208 if isinstance(memory
, tuple):
209 read_only
, memory
= memory
212 mapaddr
= self
.address_map(name
, memory
)
215 sram_bus
= Interface(*ifargs
, **ifkwargs
)
216 mmap
= SRAM(memory
, mapaddr
, read_only
=read_only
,
218 self
.submodules
+= mmap
219 csrs
+= mmap
.get_csrs()
220 self
.srams
.append((name
, memory
, mapaddr
, mmap
))
221 if hasattr(obj
, "get_constants"):
222 for constant
in obj
.get_constants():
223 self
.constants
.append((name
, constant
))
225 mapaddr
= self
.address_map(name
, None)
228 bank_bus
= Interface(*ifargs
, **ifkwargs
)
229 rmap
= CSRBank(csrs
, mapaddr
, bus
=bank_bus
)
230 self
.submodules
+= rmap
231 self
.banks
.append((name
, csrs
, mapaddr
, rmap
))
234 return [rmap
for name
, csrs
, mapaddr
, rmap
in self
.banks
]
237 return [mmap
for name
, memory
, mapaddr
, mmap
in self
.srams
]
240 return [i
.bus
for i
in self
.get_rmaps() + self
.get_mmaps()]