e1de6c327bd9f59a81281f645df997a939b1dbd9
[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 = ('o', 'o') if dirn else ('i', '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 print ("make_jtag_ioconn", scan_idx)
71 print ("cpupads", cpupads)
72 print ("iopads", iopads)
73 print ("pin", fn, pin, iotype, pin_name)
74 print ("cpu fn", cpu)
75 print ("io fn", io)
76 name = "%s_%s" % (fn, pin)
77 print ("name", name)
78 sigs = []
79
80 if iotype in (IOType.In, IOType.Out):
81 ps = pin.split("_")
82 if pin == 'clock' and fn == 'sdr':
83 cpup = cpu
84 iop = io
85 elif len(ps) == 2 and ps[-1].isdigit():
86 pin, idx = ps
87 idx = int(idx)
88 print ("ps split", pin, idx)
89 cpup = getattr(cpu, pin)[idx]
90 iop = getattr(io, pin)[idx]
91 elif pin.isdigit():
92 idx = int(pin)
93 print ("digit", idx)
94 cpup = cpu[idx]
95 iop = io[idx]
96 else:
97 cpup = getattr(cpu, pin)
98 iop = getattr(io, pin)
99
100 if iotype == IOType.Out:
101 # output from the pad is routed through C4M JTAG and so
102 # is an *INPUT* into core. ls180soc connects this to "real" peripheral
103 make_pad(res, True, name, "o", cpup, iop)
104
105 elif iotype == IOType.In:
106 # input to the pad is routed through C4M JTAG and so
107 # is an *OUTPUT* into core. ls180soc connects this to "real" peripheral
108 make_pad(res, False, name, "i", cpup, iop)
109
110 elif iotype == IOType.InTriOut:
111 if fn == 'gpio': # sigh decode GPIO special-case
112 idx = int(pin[1:])
113 oe_idx = idx
114 pfx = ''
115 elif fn.startswith('sd') and pin.startswith('data'):
116 idx = int(pin[-1])
117 oe_idx = 0
118 pfx = pin[:-1]+"_"
119 elif fn == 'sdr':
120 idx = int(pin.split('_')[-1])
121 oe_idx = 0
122 pfx = pin.split('_')[0]+"_"
123 else:
124 idx = 0
125 oe_idx = 0
126 pfx = pin+"_"
127 print ("gpio tri", fn, pin, iotype, pin_name, scan_idx, idx)
128 cpup, iop = get_field(cpu, pfx+"i")[idx], get_field(io, pfx+"i")[idx]
129 make_pad(res, False, name, "i", cpup, iop)
130 cpup, iop = get_field(cpu, pfx+"o")[idx], get_field(io, pfx+"o")[idx]
131 make_pad(res, True, name, "o", cpup, iop)
132 cpup, iop = get_field(cpu, pfx+"oe")[oe_idx], \
133 get_field(io, pfx+"oe")[oe_idx]
134 make_pad(res, True, name, "oe", cpup, iop)
135
136 if iotype in (IOType.In, IOType.InTriOut):
137 sigs.append(("i", 1))
138 if iotype in (IOType.Out, IOType.TriOut, IOType.InTriOut):
139 sigs.append(("o", 1))
140 if iotype in (IOType.TriOut, IOType.InTriOut):
141 sigs.append(("oe", 1))
142
143
144 class LibreSoC(CPU):
145 name = "libre_soc"
146 human_name = "Libre-SoC"
147 variants = CPU_VARIANTS
148 endianness = "little"
149 gcc_triple = ("powerpc64le-linux", "powerpc64le-linux-gnu")
150 linker_output_format = "elf64-powerpcle"
151 nop = "nop"
152 io_regions = {0xc0000000: 0x10000000} # origin, length
153
154 @property
155 def mem_map(self):
156 return {"csr": 0xc0000000}
157
158 @property
159 def gcc_flags(self):
160 flags = "-m64 "
161 flags += "-mabi=elfv2 "
162 flags += "-msoft-float "
163 flags += "-mno-string "
164 flags += "-mno-multiple "
165 flags += "-mno-vsx "
166 flags += "-mno-altivec "
167 flags += "-mlittle-endian "
168 flags += "-mstrict-align "
169 flags += "-fno-stack-protector "
170 flags += "-mcmodel=small "
171 flags += "-D__microwatt__ "
172 return flags
173
174 def __init__(self, platform, variant="standard"):
175 self.platform = platform
176 self.variant = variant
177 self.reset = Signal()
178
179 irq_en = "noirq" not in variant
180
181 if irq_en:
182 self.interrupt = Signal(16)
183
184 if variant == "standard32":
185 self.data_width = 32
186 self.dbus = dbus = wb.Interface(data_width=32, adr_width=30)
187 else:
188 self.dbus = dbus = wb.Interface(data_width=64, adr_width=29)
189 self.data_width = 64
190 self.ibus = ibus = wb.Interface(data_width=64, adr_width=29)
191
192 self.xics_icp = icp = wb.Interface(data_width=32, adr_width=30)
193 self.xics_ics = ics = wb.Interface(data_width=32, adr_width=30)
194
195 jtag_en = ('jtag' in variant) or ('ls180' in variant)
196
197 if "testgpio" in variant:
198 self.simple_gpio = gpio = wb.Interface(data_width=32, adr_width=30)
199 if jtag_en:
200 self.jtag_wb = jtag_wb = wb.Interface(data_width=64, adr_width=29)
201
202 self.srams = srams = []
203 if "sram4k" in variant:
204 for i in range(4):
205 srams.append(wb.Interface(data_width=64, adr_width=29))
206
207 self.periph_buses = [ibus, dbus]
208 self.memory_buses = []
209
210 if jtag_en:
211 self.periph_buses.append(jtag_wb)
212 self.jtag_tck = Signal(1)
213 self.jtag_tms = Signal(1)
214 self.jtag_tdi = Signal(1)
215 self.jtag_tdo = Signal(1)
216 else:
217 self.dmi_addr = Signal(4)
218 self.dmi_din = Signal(64)
219 self.dmi_dout = Signal(64)
220 self.dmi_wr = Signal(1)
221 self.dmi_ack = Signal(1)
222 self.dmi_req = Signal(1)
223
224 # # #
225
226 self.cpu_params = dict(
227 # Clock / Reset
228 i_clk = ClockSignal(),
229 i_rst = ResetSignal() | self.reset,
230
231 # Monitoring / Debugging
232 i_pc_i = 0,
233 i_pc_i_ok = 0,
234 i_core_bigendian_i = 0, # Signal(),
235 o_busy_o = Signal(), # not connected
236 o_memerr_o = Signal(), # not connected
237 o_pc_o = Signal(64), # not connected
238 )
239
240 if irq_en:
241 # interrupts
242 self.cpu_params['i_int_level_i'] = self.interrupt
243
244 if jtag_en:
245 self.cpu_params.update(dict(
246 # JTAG Debug bus
247 o_TAP_bus__tdo = self.jtag_tdo,
248 i_TAP_bus__tdi = self.jtag_tdi,
249 i_TAP_bus__tms = self.jtag_tms,
250 i_TAP_bus__tck = self.jtag_tck,
251 ))
252 else:
253 self.cpu_params.update(dict(
254 # DMI Debug bus
255 i_dmi_addr_i = self.dmi_addr,
256 i_dmi_din = self.dmi_din,
257 o_dmi_dout = self.dmi_dout,
258 i_dmi_req_i = self.dmi_req,
259 i_dmi_we_i = self.dmi_wr,
260 o_dmi_ack_o = self.dmi_ack,
261 ))
262
263 # add clock select, pll output
264 if "ls180" in variant:
265 self.pll_18_o = Signal()
266 self.clk_sel = Signal(2)
267 self.pll_lck_o = Signal()
268 self.cpu_params['i_clk_sel_i'] = self.clk_sel
269 self.cpu_params['o_pll_18_o'] = self.pll_18_o
270 self.cpu_params['o_pll_lck_o'] = self.pll_lck_o
271
272 # add wishbone buses to cpu params
273 self.cpu_params.update(make_wb_bus("ibus", ibus, True))
274 self.cpu_params.update(make_wb_bus("dbus", dbus, True))
275 self.cpu_params.update(make_wb_slave("ics_wb", ics, True))
276 self.cpu_params.update(make_wb_slave("icp_wb", icp, True))
277 if "testgpio" in variant:
278 self.cpu_params.update(make_wb_slave("gpio_wb", gpio))
279 if jtag_en:
280 self.cpu_params.update(make_wb_bus("jtag_wb", jtag_wb, simple=True))
281 if "sram4k" in variant:
282 for i, sram in enumerate(srams):
283 self.cpu_params.update(make_wb_slave("sram4k_%d_wb" % i,
284 sram, simple=True))
285
286 # and set ibus advanced tags to zero (disable)
287 self.cpu_params['i_ibus__cti'] = 0
288 self.cpu_params['i_ibus__bte'] = 0
289 self.cpu_params['i_dbus__cti'] = 0
290 self.cpu_params['i_dbus__bte'] = 0
291
292 if "ls180" in variant:
293 # urr yuk. have to expose iopads / pins from core to litex
294 # then back again. cut _some_ of that out by connecting
295 self.padresources = io()
296 self.pad_cm = ConstraintManager(self.padresources, [])
297 self.cpupads = {}
298 iopads = {}
299 litexmap = {}
300 subset = {'uart', 'mtwi', 'eint', 'gpio', 'mspi0', 'mspi1',
301 'pwm', 'sd0', 'sdr'}
302 for periph in subset:
303 origperiph = periph
304 num = None
305 if periph[-1].isdigit():
306 periph, num = periph[:-1], int(periph[-1])
307 print ("periph request", periph, num)
308 if periph == 'mspi':
309 if num == 0:
310 periph, num = 'spimaster', None
311 else:
312 periph, num = 'spisdcard', None
313 elif periph == 'sdr':
314 periph = 'sdram'
315 elif periph == 'mtwi':
316 periph = 'i2c'
317 elif periph == 'sd':
318 periph, num = 'sdcard', None
319 litexmap[origperiph] = (periph, num)
320 self.cpupads[origperiph] = platform.request(periph, num)
321 iopads[origperiph] = self.pad_cm.request(periph, num)
322 if periph == 'sdram':
323 # special-case sdram clock
324 ck = platform.request("sdram_clock")
325 self.cpupads['sdram_clock'] = ck
326 ck = self.pad_cm.request("sdram_clock")
327 iopads['sdram_clock'] = ck
328
329 pinset = get_pinspecs(subset=subset)
330 p = Pins(pinset)
331 for pin in list(p):
332 make_jtag_ioconn(self.cpu_params, pin, self.cpupads, iopads)
333
334 # add verilog sources
335 self.add_sources(platform)
336
337 def set_reset_address(self, reset_address):
338 assert not hasattr(self, "reset_address")
339 self.reset_address = reset_address
340 assert reset_address == 0x00000000
341
342 @staticmethod
343 def add_sources(platform):
344 cdir = os.path.dirname(__file__)
345 platform.add_source(os.path.join(cdir, "libresoc.v"))
346
347 def do_finalize(self):
348 self.specials += Instance("test_issuer", **self.cpu_params)
349