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