3340a0c4d13cd65960b80b85eccbea04eb61fda7
[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 soc.config.pinouts import get_pinspecs
9 from soc.debug.jtag import Pins
10 from c4m.nmigen.jtag.tap import IOType
11
12 from libresoc.ls180 import io
13 from litex.build.generic_platform import ConstraintManager
14
15
16 CPU_VARIANTS = ["standard", "standard32", "standardjtag",
17 "standardjtagtestgpio", "ls180", "ls180sram4k",
18 "standardjtagnoirq"]
19
20
21 def make_wb_bus(prefix, obj, simple=False):
22 res = {}
23 outpins = ['stb', 'cyc', 'we', 'adr', 'dat_w', 'sel']
24 if not simple:
25 outpins += ['cti', 'bte']
26 for o in outpins:
27 res['o_%s__%s' % (prefix, o)] = getattr(obj, o)
28 for i in ['ack', 'err', 'dat_r']:
29 res['i_%s__%s' % (prefix, i)] = getattr(obj, i)
30 return res
31
32 def make_wb_slave(prefix, obj, simple=False):
33 res = {}
34 inpins = ['stb', 'cyc', 'we', 'adr', 'dat_w', 'sel']
35 if not simple:
36 inpins += ['cti', 'bte']
37 for i in inpins:
38 res['i_%s__%s' % (prefix, i)] = getattr(obj, i)
39 for o in ['ack', 'err', 'dat_r']:
40 res['o_%s__%s' % (prefix, o)] = getattr(obj, o)
41 return res
42
43 def make_pad(res, dirn, name, suffix, cpup, iop):
44 cpud, iod = ('i', 'o') if dirn else ('o', 'i')
45 cname = '%s_%s__core__%s' % (cpud, name, suffix)
46 pname = '%s_%s__pad__%s' % (iod, name, suffix)
47 print ("make pad", name, dirn, cpud, iod, cname, pname, suffix, cpup, iop)
48 res[cname], res[pname] = cpup, iop
49
50 def get_field(rec, name):
51 for f in rec.layout:
52 f = f[0]
53 print ("get_field", f, name)
54 for f in rec.layout:
55 f = f[0]
56 if f.endswith(name):
57 return getattr(rec, f)
58
59
60 def make_jtag_ioconn(res, pin, cpupads, iopads):
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 = 0
121 pfx = pin[:-1]+"_"
122 elif fn == 'sdr':
123 idx = int(pin.split('_')[-1])
124 oe_idx = 0
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=64, adr_width=29)
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 = 0,
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:
273 self.pll_18_o = Signal()
274 self.clk_sel = Signal(2)
275 self.pll_lck_o = Signal()
276 self.cpu_params['i_clk_sel_i'] = self.clk_sel
277 self.cpu_params['o_pll_18_o'] = self.pll_18_o
278 self.cpu_params['o_pll_lck_o'] = self.pll_lck_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 # urr yuk. have to expose iopads / pins from core to litex
302 # then back again. cut _some_ of that out by connecting
303 self.padresources = io()
304 self.pad_cm = ConstraintManager(self.padresources, [])
305 self.cpupads = {}
306 iopads = {}
307 litexmap = {}
308 subset = {'uart', 'mtwi', 'eint', 'mspi0',
309 'sdr'}
310 subset.add('gpio')
311 #subset.add('pwm')
312 #subset.add('mspi1')
313 #subset.add('sd0')
314 for periph in subset:
315 origperiph = periph
316 num = None
317 if periph[-1].isdigit():
318 periph, num = periph[:-1], int(periph[-1])
319 print ("periph request", periph, num)
320 if periph == 'mspi':
321 if num == 0:
322 periph, num = 'spimaster', None
323 else:
324 periph, num = 'spisdcard', None
325 elif periph == 'sdr':
326 periph = 'sdram'
327 elif periph == 'mtwi':
328 periph = 'i2c'
329 elif periph == 'sd':
330 periph, num = 'sdcard', None
331 litexmap[origperiph] = (periph, num)
332 self.cpupads[origperiph] = self.pad_cm.request(periph, num)
333 iopads[origperiph] = platform.request(periph, num)
334 #if periph == 'sdram':
335 # # special-case sdram clock
336 # ck = self.pad_cm.request("sdram_clock")
337 # self.cpupads['sdram_clock'] = ck
338 # ck = platform.request("sdram_clock")
339 # iopads['sdram_clock'] = ck
340
341 pinset = get_pinspecs(subset=subset)
342 p = Pins(pinset)
343 for pin in list(p):
344 make_jtag_ioconn(self.cpu_params, pin, self.cpupads, iopads)
345
346 # add verilog sources
347 self.add_sources(platform)
348
349 def set_reset_address(self, reset_address):
350 assert not hasattr(self, "reset_address")
351 self.reset_address = reset_address
352 assert reset_address == 0x00000000
353
354 @staticmethod
355 def add_sources(platform):
356 cdir = os.path.dirname(__file__)
357 platform.add_source(os.path.join(cdir, "libresoc.v"))
358
359 def do_finalize(self):
360 self.specials += Instance("test_issuer", **self.cpu_params)
361