update README
[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", "powerpc64le-unknown-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 self.cpu_clk = ClockSignal()
190
191 irq_en = "noirq" not in variant
192
193 if irq_en:
194 self.interrupt = Signal(16)
195
196 if variant == "standard32":
197 self.data_width = 32
198 self.dbus = dbus = wb.Interface(data_width=32, adr_width=30)
199 else:
200 self.dbus = dbus = wb.Interface(data_width=64, adr_width=29)
201 self.data_width = 64
202 self.ibus = ibus = wb.Interface(data_width=64, adr_width=29)
203
204 self.xics_icp = icp = wb.Interface(data_width=32, adr_width=30)
205 self.xics_ics = ics = wb.Interface(data_width=32, adr_width=30)
206
207 jtag_en = ('jtag' in variant) or ('ls180' in variant)
208
209 if "testgpio" in variant:
210 self.simple_gpio = gpio = wb.Interface(data_width=32, adr_width=30)
211 if jtag_en:
212 self.jtag_wb = jtag_wb = wb.Interface(data_width=32, adr_width=30)
213
214 self.srams = srams = []
215 if "sram4k" in variant:
216 for i in range(4):
217 srams.append(wb.Interface(data_width=64, adr_width=29))
218
219 self.periph_buses = [ibus, dbus]
220 self.memory_buses = []
221
222 if jtag_en:
223 self.periph_buses.append(jtag_wb)
224 self.jtag_tck = Signal(1)
225 self.jtag_tms = Signal(1)
226 self.jtag_tdi = Signal(1)
227 self.jtag_tdo = Signal(1)
228 else:
229 self.dmi_addr = Signal(4)
230 self.dmi_din = Signal(64)
231 self.dmi_dout = Signal(64)
232 self.dmi_wr = Signal(1)
233 self.dmi_ack = Signal(1)
234 self.dmi_req = Signal(1)
235
236 # # #
237
238 self.cpu_params = dict(
239 # Clock / Reset
240 i_clk = self.cpu_clk,
241 i_rst = ResetSignal() | self.reset,
242
243 # Monitoring / Debugging
244 i_core_bigendian_i = 0, # Signal(),
245 o_busy_o = Signal(), # not connected
246 o_memerr_o = Signal(), # not connected
247 o_pc_o = Signal(64), # not connected
248 )
249
250 # these have been taken out
251 #self.cpu_params['i_pc_i'] = Signal(64)
252 #self.cpu_params['i_pc_i_ok'] = 0
253
254 if irq_en:
255 # interrupts
256 self.cpu_params['i_int_level_i'] = self.interrupt
257
258 if jtag_en:
259 self.cpu_params.update(dict(
260 # JTAG Debug bus
261 o_TAP_bus__tdo = self.jtag_tdo,
262 i_TAP_bus__tdi = self.jtag_tdi,
263 i_TAP_bus__tms = self.jtag_tms,
264 i_TAP_bus__tck = self.jtag_tck,
265 ))
266 else:
267 self.cpu_params.update(dict(
268 # DMI Debug bus
269 i_dmi_addr_i = self.dmi_addr,
270 i_dmi_din = self.dmi_din,
271 o_dmi_dout = self.dmi_dout,
272 i_dmi_req_i = self.dmi_req,
273 i_dmi_we_i = self.dmi_wr,
274 o_dmi_ack_o = self.dmi_ack,
275 ))
276
277 # add clock select, pll output
278 if "ls180" in variant and "pll" not in variant:
279 self.pll_vco_o = Signal()
280 self.clk_sel = Signal(2)
281 self.pll_test_o = Signal()
282 self.pll_24_i = Signal()
283 self.pllclk_o = ClockSignal("pll")
284 self.cpu_params['i_clk_sel_i'] = self.clk_sel
285 self.cpu_params['i_clk_24_i'] = self.pll_24_i
286 self.cpu_params['o_pll_vco_o'] = self.pll_vco_o
287 self.cpu_params['o_pll_test_o'] = self.pll_test_o
288 self.cpu_params['o_pllclk_clk'] = self.pllclk_o
289
290 # add wishbone buses to cpu params
291 self.cpu_params.update(make_wb_bus("ibus", ibus, True))
292 self.cpu_params.update(make_wb_bus("dbus", dbus, True))
293 self.cpu_params.update(make_wb_slave("ics_wb", ics, True))
294 self.cpu_params.update(make_wb_slave("icp_wb", icp, True))
295 if "testgpio" in variant:
296 self.cpu_params.update(make_wb_slave("gpio_wb", gpio))
297 if jtag_en:
298 self.cpu_params.update(make_wb_bus("jtag_wb", jtag_wb, simple=True))
299 if "sram4k" in variant:
300 for i, sram in enumerate(srams):
301 self.cpu_params.update(make_wb_slave("sram4k_%d_wb" % i,
302 sram, simple=True,
303 err=False))
304
305 # and set ibus advanced tags to zero (disable)
306 self.cpu_params['i_ibus__cti'] = 0
307 self.cpu_params['i_ibus__bte'] = 0
308 self.cpu_params['i_dbus__cti'] = 0
309 self.cpu_params['i_dbus__bte'] = 0
310
311 if "ls180" in variant:
312 # XXX normally this is NOT done, however to avoid import problems
313 # in litex, move the import into where it is optionally called
314 # then, for non-ls180 platforms, huge numbers of dependencies
315 # behind these simple-looking imports are not needed.
316 # For normal FPGA usage ("standard" variants) you DO NOT need this.
317 # it is ONLY for ASICs, for managing JTAG TAP Boundary Scans.
318
319 from soc.config.pinouts import get_pinspecs
320 from soc.debug.jtag import Pins
321 from libresoc.ls180 import io
322
323 # urr yuk. have to expose iopads / pins from core to litex
324 # then back again. cut _some_ of that out by connecting up
325 # padresources. this mirrors what is done inside litex
326 self.padresources = io()
327 self.pad_cm = ConstraintManager(self.padresources, [])
328 self.cpupads = {}
329 iopads = {}
330 litexmap = {}
331 subset = {'uart', 'mtwi', 'eint', 'mspi0',
332 'sdr'}
333 subset.add('gpio')
334 #subset.add('pwm')
335 #subset.add('mspi1')
336 #subset.add('sd0')
337 for periph in subset:
338 origperiph = periph
339 num = None
340 if periph[-1].isdigit():
341 periph, num = periph[:-1], int(periph[-1])
342 print ("periph request", periph, num)
343 if periph == 'mspi':
344 if num == 0:
345 periph, num = 'spimaster', None
346 else:
347 periph, num = 'spisdcard', None
348 elif periph == 'sdr':
349 periph = 'sdram'
350 elif periph == 'mtwi':
351 periph = 'i2c'
352 elif periph == 'sd':
353 periph, num = 'sdcard', None
354 litexmap[origperiph] = (periph, num)
355 self.cpupads[origperiph] = self.pad_cm.request(periph, num)
356 iopads[origperiph] = platform.request(periph, num)
357 #if periph == 'sdram':
358 # # special-case sdram clock
359 # ck = self.pad_cm.request("sdram_clock")
360 # self.cpupads['sdram_clock'] = ck
361 # ck = platform.request("sdram_clock")
362 # iopads['sdram_clock'] = ck
363
364 # for the 180nm ASIC, obtain the pinspecs so that JTAG can be
365 # routed in and back out again. litex is such hell (migen)
366 # that trying to create an auto-generated boundary scan in
367 # migen is just not sane.
368 pinset = get_pinspecs(subset=subset)
369 p = Pins(pinset)
370 for pin in list(p):
371 make_jtag_ioconn(self.cpu_params, pin, self.cpupads, iopads)
372
373 # add verilog sources
374 self.add_sources(platform)
375
376 def set_reset_address(self, reset_address):
377 assert not hasattr(self, "reset_address")
378 self.reset_address = reset_address
379 assert reset_address == 0x00000000
380
381 @staticmethod
382 def add_sources(platform):
383 cdir = os.path.dirname(__file__)
384 platform.add_source(os.path.join(cdir, "libresoc.v"))
385 platform.add_source(os.path.join(cdir, "pll.v"))
386 platform.add_source(os.path.join(cdir, "SPBlock_512W64B8W.v"))
387
388 def do_finalize(self):
389 self.specials += Instance("test_issuer", **self.cpu_params)
390