remove wb err signal from sram4k
[libresoc-litex.git] / libresoc / core.py
1 import os
2
3 from migen import ClockSignal, ResetSignal, Signal, Instance, Cat
4
5 from litex.soc.interconnect import wishbone as wb
6 from litex.soc.cores.cpu import CPU
7
8 from litex.build.generic_platform import ConstraintManager
9
10
11 CPU_VARIANTS = ["standard", "standard32", "standardjtag",
12 "standardjtagtestgpio", "ls180", "ls180sram4k",
13 "ls180nopll",
14 "standardjtagnoirq"]
15
16
17 def make_wb_bus(prefix, obj, simple=False):
18 res = {}
19 outpins = ['stb', 'cyc', 'we', 'adr', 'dat_w', 'sel']
20 if not simple:
21 outpins += ['cti', 'bte']
22 for o in outpins:
23 res['o_%s__%s' % (prefix, o)] = getattr(obj, o)
24 for i in ['ack', 'err', 'dat_r']:
25 res['i_%s__%s' % (prefix, i)] = getattr(obj, i)
26 return res
27
28 def make_wb_slave(prefix, obj, simple=False, err=True):
29 res = {}
30 inpins = ['stb', 'cyc', 'we', 'adr', 'dat_w', 'sel']
31 if not simple:
32 inpins += ['cti', 'bte']
33 for i in inpins:
34 res['i_%s__%s' % (prefix, i)] = getattr(obj, i)
35 outpins = ['ack', 'dat_r']
36 if err:
37 outpins.append('err')
38 for o in outpins:
39 res['o_%s__%s' % (prefix, o)] = getattr(obj, o)
40 return res
41
42 def make_pad(res, dirn, name, suffix, cpup, iop):
43 cpud, iod = ('i', 'o') if dirn else ('o', 'i')
44 cname = '%s_%s__core__%s' % (cpud, name, suffix)
45 pname = '%s_%s__pad__%s' % (iod, name, suffix)
46 print ("make pad", name, dirn, cpud, iod, cname, pname, suffix, cpup, iop)
47 res[cname], res[pname] = cpup, iop
48
49 def get_field(rec, name):
50 for f in rec.layout:
51 f = f[0]
52 print ("get_field", f, name)
53 for f in rec.layout:
54 f = f[0]
55 if f.endswith(name):
56 return getattr(rec, f)
57
58
59 def make_jtag_ioconn(res, pin, cpupads, iopads):
60 # XXX normally this is NOT done, however to avoid import problems
61 # in litex, move the import into where it is optionally called
62 from c4m.nmigen.jtag.tap import IOType
63
64 (fn, pin, iotype, pin_name, scan_idx) = pin
65 #serial_tx__core__o, serial_rx__pad__i,
66 # special-case sdram_clock
67 #if pin == 'clock' and fn == 'sdr':
68 # cpu = cpupads['sdram_clock']
69 # io = iopads['sdram_clock']
70 #else:
71 # cpu = cpupads[fn]
72 # io = iopads[fn]
73 cpu = cpupads[fn]
74 io = iopads[fn]
75 print ("make_jtag_ioconn", scan_idx)
76 print ("cpupads", cpupads)
77 print ("iopads", iopads)
78 print ("pin", fn, pin, iotype, pin_name)
79 print ("cpu fn", cpu)
80 print ("io fn", io)
81 name = "%s_%s" % (fn, pin)
82 print ("name", name)
83 sigs = []
84
85 if iotype in (IOType.In, IOType.Out):
86 ps = pin.split("_")
87 #if pin == 'clock' and fn == 'sdr':
88 # cpup = cpu
89 # iop = io
90 if len(ps) == 2 and ps[-1].isdigit():
91 pin, idx = ps
92 idx = int(idx)
93 print ("ps split", pin, idx)
94 cpup = getattr(cpu, pin)[idx]
95 iop = getattr(io, pin)[idx]
96 elif pin.isdigit() and fn != 'eint':
97 idx = int(pin)
98 print ("digit", idx)
99 cpup = cpu[idx]
100 iop = io[idx]
101 else:
102 print ("attr", cpu)
103 cpup = getattr(cpu, pin)
104 iop = getattr(io, pin)
105
106 if iotype == IOType.Out:
107 # output from the pad is routed through C4M JTAG and so
108 # is an *INPUT* into core. ls180soc connects this to "real" peripheral
109 make_pad(res, True, name, "o", cpup, iop)
110
111 elif iotype == IOType.In:
112 # input to the pad is routed through C4M JTAG and so
113 # is an *OUTPUT* into core. ls180soc connects this to "real" peripheral
114 make_pad(res, False, name, "i", cpup, iop)
115
116 elif iotype == IOType.InTriOut:
117 if fn == 'gpio': # sigh decode GPIO special-case
118 idx = int(pin[1:])
119 oe_idx = idx
120 pfx = ''
121 elif fn.startswith('sd') and pin.startswith('data'):
122 idx = int(pin[-1])
123 oe_idx = idx
124 pfx = pin[:-1]+"_"
125 elif fn == 'sdr':
126 idx = int(pin.split('_')[-1])
127 oe_idx = idx
128 pfx = pin.split('_')[0]+"_"
129 else:
130 idx = 0
131 oe_idx = 0
132 pfx = pin+"_"
133 print ("gpio tri", fn, pin, iotype, pin_name, scan_idx, idx)
134 # i pads
135 cpup, iop = get_field(cpu, pfx+"i")[idx], \
136 get_field(io, pfx+"i")[idx]
137 make_pad(res, False, name, "i", cpup, iop)
138 # o pads
139 cpup, iop = get_field(cpu, pfx+"o")[idx], \
140 get_field(io, pfx+"o")[idx]
141 make_pad(res, True, name, "o", cpup, iop)
142 # oe pads
143 cpup, iop = get_field(cpu, pfx+"oe")[oe_idx], \
144 get_field(io, pfx+"oe")[oe_idx]
145 make_pad(res, True, name, "oe", cpup, iop)
146
147 if iotype in (IOType.In, IOType.InTriOut):
148 sigs.append(("i", 1))
149 if iotype in (IOType.Out, IOType.TriOut, IOType.InTriOut):
150 sigs.append(("o", 1))
151 if iotype in (IOType.TriOut, IOType.InTriOut):
152 sigs.append(("oe", 1))
153
154
155 class LibreSoC(CPU):
156 name = "libre_soc"
157 human_name = "Libre-SoC"
158 variants = CPU_VARIANTS
159 endianness = "little"
160 gcc_triple = ("powerpc64le-linux", "powerpc64le-linux-gnu")
161 linker_output_format = "elf64-powerpcle"
162 nop = "nop"
163 io_regions = {0xc0000000: 0x10000000} # origin, length
164
165 @property
166 def mem_map(self):
167 return {"csr": 0xc0000000}
168
169 @property
170 def gcc_flags(self):
171 flags = "-m64 "
172 flags += "-mabi=elfv2 "
173 flags += "-msoft-float "
174 flags += "-mno-string "
175 flags += "-mno-multiple "
176 flags += "-mno-vsx "
177 flags += "-mno-altivec "
178 flags += "-mlittle-endian "
179 flags += "-mstrict-align "
180 flags += "-fno-stack-protector "
181 flags += "-mcmodel=small "
182 flags += "-D__microwatt__ "
183 return flags
184
185 def __init__(self, platform, variant="standard"):
186 self.platform = platform
187 self.variant = variant
188 self.reset = Signal()
189
190 irq_en = "noirq" not in variant
191
192 if irq_en:
193 self.interrupt = Signal(16)
194
195 if variant == "standard32":
196 self.data_width = 32
197 self.dbus = dbus = wb.Interface(data_width=32, adr_width=30)
198 else:
199 self.dbus = dbus = wb.Interface(data_width=64, adr_width=29)
200 self.data_width = 64
201 self.ibus = ibus = wb.Interface(data_width=64, adr_width=29)
202
203 self.xics_icp = icp = wb.Interface(data_width=32, adr_width=30)
204 self.xics_ics = ics = wb.Interface(data_width=32, adr_width=30)
205
206 jtag_en = ('jtag' in variant) or ('ls180' in variant)
207
208 if "testgpio" in variant:
209 self.simple_gpio = gpio = wb.Interface(data_width=32, adr_width=30)
210 if jtag_en:
211 self.jtag_wb = jtag_wb = wb.Interface(data_width=32, adr_width=30)
212
213 self.srams = srams = []
214 if "sram4k" in variant:
215 for i in range(4):
216 srams.append(wb.Interface(data_width=64, adr_width=29))
217
218 self.periph_buses = [ibus, dbus]
219 self.memory_buses = []
220
221 if jtag_en:
222 self.periph_buses.append(jtag_wb)
223 self.jtag_tck = Signal(1)
224 self.jtag_tms = Signal(1)
225 self.jtag_tdi = Signal(1)
226 self.jtag_tdo = Signal(1)
227 else:
228 self.dmi_addr = Signal(4)
229 self.dmi_din = Signal(64)
230 self.dmi_dout = Signal(64)
231 self.dmi_wr = Signal(1)
232 self.dmi_ack = Signal(1)
233 self.dmi_req = Signal(1)
234
235 # # #
236
237 self.cpu_params = dict(
238 # Clock / Reset
239 i_clk = ClockSignal(),
240 i_rst = ResetSignal() | self.reset,
241
242 # Monitoring / Debugging
243 i_pc_i = Signal(64),
244 i_pc_i_ok = 0,
245 i_core_bigendian_i = 0, # Signal(),
246 o_busy_o = Signal(), # not connected
247 o_memerr_o = Signal(), # not connected
248 o_pc_o = Signal(64), # not connected
249 )
250
251 if irq_en:
252 # interrupts
253 self.cpu_params['i_int_level_i'] = self.interrupt
254
255 if jtag_en:
256 self.cpu_params.update(dict(
257 # JTAG Debug bus
258 o_TAP_bus__tdo = self.jtag_tdo,
259 i_TAP_bus__tdi = self.jtag_tdi,
260 i_TAP_bus__tms = self.jtag_tms,
261 i_TAP_bus__tck = self.jtag_tck,
262 ))
263 else:
264 self.cpu_params.update(dict(
265 # DMI Debug bus
266 i_dmi_addr_i = self.dmi_addr,
267 i_dmi_din = self.dmi_din,
268 o_dmi_dout = self.dmi_dout,
269 i_dmi_req_i = self.dmi_req,
270 i_dmi_we_i = self.dmi_wr,
271 o_dmi_ack_o = self.dmi_ack,
272 ))
273
274 # add clock select, pll output
275 if "ls180" in variant and "pll" not in variant:
276 self.pll_vco_o = Signal()
277 self.clk_sel = Signal(2)
278 self.pll_test_o = Signal()
279 self.cpu_params['i_clk_sel_i'] = self.clk_sel
280 self.cpu_params['o_pll_vco_o'] = self.pll_vco_o
281 self.cpu_params['o_pll_test_o'] = self.pll_test_o
282
283 # add wishbone buses to cpu params
284 self.cpu_params.update(make_wb_bus("ibus", ibus, True))
285 self.cpu_params.update(make_wb_bus("dbus", dbus, True))
286 self.cpu_params.update(make_wb_slave("ics_wb", ics, True))
287 self.cpu_params.update(make_wb_slave("icp_wb", icp, True))
288 if "testgpio" in variant:
289 self.cpu_params.update(make_wb_slave("gpio_wb", gpio))
290 if jtag_en:
291 self.cpu_params.update(make_wb_bus("jtag_wb", jtag_wb, simple=True))
292 if "sram4k" in variant:
293 for i, sram in enumerate(srams):
294 self.cpu_params.update(make_wb_slave("sram4k_%d_wb" % i,
295 sram, simple=True,
296 err=False))
297
298 # and set ibus advanced tags to zero (disable)
299 self.cpu_params['i_ibus__cti'] = 0
300 self.cpu_params['i_ibus__bte'] = 0
301 self.cpu_params['i_dbus__cti'] = 0
302 self.cpu_params['i_dbus__bte'] = 0
303
304 if "ls180" in variant:
305 # XXX normally this is NOT done, however to avoid import problems
306 # in litex, move the import into where it is optionally called
307 # then, for non-ls180 platforms, huge numbers of dependencies
308 # behind these simple-looking imports are not needed.
309 # For normal FPGA usage ("standard" variants) you DO NOT need this.
310 # it is ONLY for ASICs, for managing JTAG TAP Boundary Scans.
311
312 from soc.config.pinouts import get_pinspecs
313 from soc.debug.jtag import Pins
314 from libresoc.ls180 import io
315
316 # urr yuk. have to expose iopads / pins from core to litex
317 # then back again. cut _some_ of that out by connecting up
318 # padresources. this mirrors what is done inside litex
319 self.padresources = io()
320 self.pad_cm = ConstraintManager(self.padresources, [])
321 self.cpupads = {}
322 iopads = {}
323 litexmap = {}
324 subset = {'uart', 'mtwi', 'eint', 'mspi0',
325 'sdr'}
326 subset.add('gpio')
327 #subset.add('pwm')
328 #subset.add('mspi1')
329 #subset.add('sd0')
330 for periph in subset:
331 origperiph = periph
332 num = None
333 if periph[-1].isdigit():
334 periph, num = periph[:-1], int(periph[-1])
335 print ("periph request", periph, num)
336 if periph == 'mspi':
337 if num == 0:
338 periph, num = 'spimaster', None
339 else:
340 periph, num = 'spisdcard', None
341 elif periph == 'sdr':
342 periph = 'sdram'
343 elif periph == 'mtwi':
344 periph = 'i2c'
345 elif periph == 'sd':
346 periph, num = 'sdcard', None
347 litexmap[origperiph] = (periph, num)
348 self.cpupads[origperiph] = self.pad_cm.request(periph, num)
349 iopads[origperiph] = platform.request(periph, num)
350 #if periph == 'sdram':
351 # # special-case sdram clock
352 # ck = self.pad_cm.request("sdram_clock")
353 # self.cpupads['sdram_clock'] = ck
354 # ck = platform.request("sdram_clock")
355 # iopads['sdram_clock'] = ck
356
357 # for the 180nm ASIC, obtain the pinspecs so that JTAG can be
358 # routed in and back out again. litex is such hell (migen)
359 # that trying to create an auto-generated boundary scan in
360 # migen is just not sane.
361 pinset = get_pinspecs(subset=subset)
362 p = Pins(pinset)
363 for pin in list(p):
364 make_jtag_ioconn(self.cpu_params, pin, self.cpupads, iopads)
365
366 # add verilog sources
367 self.add_sources(platform)
368
369 def set_reset_address(self, reset_address):
370 assert not hasattr(self, "reset_address")
371 self.reset_address = reset_address
372 assert reset_address == 0x00000000
373
374 @staticmethod
375 def add_sources(platform):
376 cdir = os.path.dirname(__file__)
377 platform.add_source(os.path.join(cdir, "libresoc.v"))
378 platform.add_source(os.path.join(cdir, "SPBlock_512W64B8W.v"))
379
380 def do_finalize(self):
381 self.specials += Instance("test_issuer", **self.cpu_params)
382